mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 14:45:21 +00:00
Fixes to baseline stack alignment
1) Set the ascender/descender of an ASTextNode when the attributeString is set. Previously ascender/descender were only being computed in `setValuesFromLayoutable` and only when the attribute string was not nil. May make sense to remove the computation from `setValuesFromLayoutable` entirely. 2) Remove ability to allow different children of a stack spec to aling to different baselines. This wasn't working before and I'm not convinced it is possible to do properly/useful enough to invest the time. 3) Have all stack spec run `ASStackBaselinePositionedLayout::compute` to compute the stack's ascender and descender. Even if the stack isn't aligning its children to a baseline, the stack itself may be a child of another stack that IS aligning to a baseline.
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#import <AsyncDisplayKit/ASTextNodeTextKitHelpers.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
|
||||
|
||||
#import "ASInternalHelpers.h"
|
||||
#import "ASTextNodeRenderer.h"
|
||||
#import "ASTextNodeShadower.h"
|
||||
#import "ASEqualityHelpers.h"
|
||||
@@ -344,6 +345,12 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
|
||||
self.isAccessibilityElement = YES;
|
||||
}
|
||||
});
|
||||
|
||||
if (attributedString.length > 0) {
|
||||
CGFloat screenScale = ASScreenScale();
|
||||
self.ascender = round([[attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale;
|
||||
self.descender = round([[attributedString attribute:NSFontAttributeName atIndex:attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Text Layout
|
||||
|
||||
@@ -45,9 +45,9 @@ typedef NS_ENUM(NSUInteger, ASStackLayoutAlignItems) {
|
||||
ASStackLayoutAlignItemsCenter,
|
||||
/** Expand children to fill cross axis */
|
||||
ASStackLayoutAlignItemsStretch,
|
||||
/** Children align to their first baseline. Only available for horizontal stack nodes */
|
||||
/** Children align to their first baseline. Only available for horizontal stack spec */
|
||||
ASStackLayoutAlignItemsBaselineFirst,
|
||||
/** Children align to their last baseline. Only available for horizontal stack nodes */
|
||||
/** Children align to their last baseline. Only available for horizontal stack spec */
|
||||
ASStackLayoutAlignItemsBaselineLast,
|
||||
};
|
||||
|
||||
@@ -66,8 +66,4 @@ typedef NS_ENUM(NSUInteger, ASStackLayoutAlignSelf) {
|
||||
ASStackLayoutAlignSelfCenter,
|
||||
/** Expand to fill cross axis */
|
||||
ASStackLayoutAlignSelfStretch,
|
||||
/** Children align to their first baseline. Only available for horizontal stack nodes */
|
||||
ASStackLayoutAlignSelfBaselineFirst,
|
||||
/** Children align to their last baseline. Only available for horizontal stack nodes */
|
||||
ASStackLayoutAlignSelfBaselineLast,
|
||||
};
|
||||
|
||||
@@ -101,7 +101,6 @@
|
||||
std::vector<id<ASLayoutable>> stackChildren = std::vector<id<ASLayoutable>>();
|
||||
for (id<ASLayoutable> child in self.children) {
|
||||
stackChildren.push_back(child);
|
||||
needsBaselinePass |= child.alignSelf == ASStackLayoutAlignSelfBaselineFirst || child.alignSelf == ASStackLayoutAlignSelfBaselineLast;
|
||||
}
|
||||
|
||||
const auto unpositionedLayout = ASStackUnpositionedLayout::compute(stackChildren, style, constrainedSize);
|
||||
@@ -109,12 +108,21 @@
|
||||
|
||||
CGSize finalSize = CGSizeZero;
|
||||
NSArray *sublayouts = nil;
|
||||
if (needsBaselinePass) {
|
||||
|
||||
// regardless of whether or not this stack aligns to baseline, we should let ASStackBaselinePositionedLayout::compute find the max ascender
|
||||
// and min descender in case this spec is a child in another spec that wants to align to a baseline.
|
||||
const auto baselinePositionedLayout = ASStackBaselinePositionedLayout::compute(positionedLayout, style, constrainedSize);
|
||||
if (self.direction == ASStackLayoutDirectionVertical) {
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
self.ascender = [[self.children firstObject] ascender];
|
||||
self.descender = [[self.children lastObject] descender];
|
||||
} else {
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
self.ascender = baselinePositionedLayout.ascender;
|
||||
self.descender = baselinePositionedLayout.descender;
|
||||
}
|
||||
|
||||
if (needsBaselinePass) {
|
||||
finalSize = directionSize(style.direction, unpositionedLayout.stackDimensionSum, baselinePositionedLayout.crossSize);
|
||||
sublayouts = [NSArray arrayWithObjects:&baselinePositionedLayout.sublayouts[0] count:baselinePositionedLayout.sublayouts.size()];
|
||||
} else {
|
||||
|
||||
@@ -93,7 +93,7 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A
|
||||
const auto ascenderIt = std::max_element(positionedLayout.sublayouts.begin(), positionedLayout.sublayouts.end(), [&](const ASLayout *a, const ASLayout *b){
|
||||
return a.layoutableObject.ascender < b.layoutableObject.ascender;
|
||||
});
|
||||
const CGFloat maxAscender = baselineIt == positionedLayout.sublayouts.end() ? 0 : (*ascenderIt).layoutableObject.ascender;
|
||||
const CGFloat maxAscender = ascenderIt == positionedLayout.sublayouts.end() ? 0 : (*ascenderIt).layoutableObject.ascender;
|
||||
|
||||
/*
|
||||
Step 3: Take each child and update its layout position based on the baseline offset.
|
||||
@@ -103,9 +103,13 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A
|
||||
spacing between the two nodes is from the baseline, not the bounding box.
|
||||
|
||||
*/
|
||||
std::vector<ASLayout *> stackedChildren;
|
||||
// Only change positions of layouts this stackSpec is aligning to a baseline. Otherwise we are only here to
|
||||
// compute the min/max descender/ascender for this stack spec.
|
||||
if (style.baselineRelativeArrangement || style.alignItems == ASStackLayoutAlignItemsBaselineFirst || style.alignItems == ASStackLayoutAlignItemsBaselineLast) {
|
||||
CGPoint p = CGPointZero;
|
||||
BOOL first = YES;
|
||||
auto stackedChildren = AS::map(positionedLayout.sublayouts, [&](ASLayout *l) -> ASLayout *{
|
||||
stackedChildren = AS::map(positionedLayout.sublayouts, [&](ASLayout *l) -> ASLayout *{
|
||||
__weak id<ASLayoutable> child = l.layoutableObject;
|
||||
p = p + directionPoint(style.direction, child.spacingBefore, 0);
|
||||
if (first) {
|
||||
@@ -130,6 +134,9 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A
|
||||
|
||||
return l;
|
||||
});
|
||||
} else {
|
||||
stackedChildren = positionedLayout.sublayouts;
|
||||
}
|
||||
|
||||
/*
|
||||
Step 4: Since we have been mucking with positions, there is a chance that our cross size has changed. Imagine a node with a font size of 40
|
||||
|
||||
@@ -63,10 +63,6 @@ inline ASStackLayoutAlignItems alignment(ASStackLayoutAlignSelf childAlignment,
|
||||
return ASStackLayoutAlignItemsStart;
|
||||
case ASStackLayoutAlignSelfStretch:
|
||||
return ASStackLayoutAlignItemsStretch;
|
||||
case ASStackLayoutAlignSelfBaselineFirst:
|
||||
return ASStackLayoutAlignItemsBaselineFirst;
|
||||
case ASStackLayoutAlignSelfBaselineLast:
|
||||
return ASStackLayoutAlignItemsBaselineLast;
|
||||
case ASStackLayoutAlignSelfAuto:
|
||||
default:
|
||||
return stackAlignment;
|
||||
|
||||
Reference in New Issue
Block a user