mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
[ASStackLayoutSpec] Flex wrap fix and lineSpacing property (#472)
* ASStackUnpositionedLayout: Take spacing into account when laying out a wrapped stack. * ASStackLayoutSpec: Add the lineSpacing property. * Update CHANGELOG.md.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
## master
|
||||
|
||||
* Add your own contributions to the next release on the line below this with your name.
|
||||
- [ASStackLayoutSpec] Add lineSpacing property working with flex wrap. [Flo Vouin](https://github.com/flovouin)
|
||||
- [ASStackLayoutSpec] Fix flex wrap overflow in some cases using item spacing. [Flo Vouin](https://github.com/flovouin)
|
||||
- [ASNodeController] Add -nodeDidLayout callback. Allow switching retain behavior at runtime. [Scott Goodson](https://github.com/appleguy)
|
||||
- [ASCollectionView] Add delegate bridging and index space translation for missing UICollectionViewLayout properties. [Scott Goodson](https://github.com/appleguy)
|
||||
- [ASTextNode2] Add initial implementation for link handling. [Scott Goodson](https://github.com/appleguy) [#396](https://github.com/TextureGroup/Texture/pull/396)
|
||||
|
||||
@@ -70,6 +70,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, assign) ASStackLayoutFlexWrap flexWrap;
|
||||
/** Orientation of lines along cross axis if there are multiple lines. Defaults to ASStackLayoutAlignContentStart */
|
||||
@property (nonatomic, assign) ASStackLayoutAlignContent alignContent;
|
||||
/** If the stack spreads on multiple lines using flexWrap, the amount of space between lines. */
|
||||
@property (nonatomic, assign) CGFloat lineSpacing;
|
||||
/** Whether this stack can dispatch to other threads, regardless of which thread it's running on */
|
||||
@property (nonatomic, assign, getter=isConcurrent) BOOL concurrent;
|
||||
|
||||
@@ -105,6 +107,25 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
alignContent:(ASStackLayoutAlignContent)alignContent
|
||||
children:(NSArray<id<ASLayoutElement>> *)children AS_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
@param direction The direction of the stack view (horizontal or vertical)
|
||||
@param spacing The spacing between the children
|
||||
@param justifyContent If no children are flexible, this describes how to fill any extra space
|
||||
@param alignItems Orientation of the children along the cross axis
|
||||
@param flexWrap Whether children are stacked into a single or multiple lines
|
||||
@param alignContent Orientation of lines along cross axis if there are multiple lines
|
||||
@param lineSpacing The spacing between lines
|
||||
@param children ASLayoutElement children to be positioned.
|
||||
*/
|
||||
+ (instancetype)stackLayoutSpecWithDirection:(ASStackLayoutDirection)direction
|
||||
spacing:(CGFloat)spacing
|
||||
justifyContent:(ASStackLayoutJustifyContent)justifyContent
|
||||
alignItems:(ASStackLayoutAlignItems)alignItems
|
||||
flexWrap:(ASStackLayoutFlexWrap)flexWrap
|
||||
alignContent:(ASStackLayoutAlignContent)alignContent
|
||||
lineSpacing:(CGFloat)lineSpacing
|
||||
children:(NSArray<id<ASLayoutElement>> *)children AS_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* @return A stack layout spec with direction of ASStackLayoutDirectionVertical
|
||||
**/
|
||||
|
||||
@@ -33,17 +33,22 @@
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithDirection:ASStackLayoutDirectionHorizontal spacing:0.0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStretch flexWrap:ASStackLayoutFlexWrapNoWrap alignContent:ASStackLayoutAlignContentStart children:nil];
|
||||
return [self initWithDirection:ASStackLayoutDirectionHorizontal spacing:0.0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStretch flexWrap:ASStackLayoutFlexWrapNoWrap alignContent:ASStackLayoutAlignContentStart lineSpacing:0.0 children:nil];
|
||||
}
|
||||
|
||||
+ (instancetype)stackLayoutSpecWithDirection:(ASStackLayoutDirection)direction spacing:(CGFloat)spacing justifyContent:(ASStackLayoutJustifyContent)justifyContent alignItems:(ASStackLayoutAlignItems)alignItems children:(NSArray *)children
|
||||
{
|
||||
return [[self alloc] initWithDirection:direction spacing:spacing justifyContent:justifyContent alignItems:alignItems flexWrap:ASStackLayoutFlexWrapNoWrap alignContent:ASStackLayoutAlignContentStart children:children];
|
||||
return [[self alloc] initWithDirection:direction spacing:spacing justifyContent:justifyContent alignItems:alignItems flexWrap:ASStackLayoutFlexWrapNoWrap alignContent:ASStackLayoutAlignContentStart lineSpacing: 0.0 children:children];
|
||||
}
|
||||
|
||||
+ (instancetype)stackLayoutSpecWithDirection:(ASStackLayoutDirection)direction spacing:(CGFloat)spacing justifyContent:(ASStackLayoutJustifyContent)justifyContent alignItems:(ASStackLayoutAlignItems)alignItems flexWrap:(ASStackLayoutFlexWrap)flexWrap alignContent:(ASStackLayoutAlignContent)alignContent children:(NSArray<id<ASLayoutElement>> *)children
|
||||
{
|
||||
return [[self alloc] initWithDirection:direction spacing:spacing justifyContent:justifyContent alignItems:alignItems flexWrap:flexWrap alignContent:alignContent children:children];
|
||||
return [[self alloc] initWithDirection:direction spacing:spacing justifyContent:justifyContent alignItems:alignItems flexWrap:flexWrap alignContent:alignContent lineSpacing:0.0 children:children];
|
||||
}
|
||||
|
||||
+ (instancetype)stackLayoutSpecWithDirection:(ASStackLayoutDirection)direction spacing:(CGFloat)spacing justifyContent:(ASStackLayoutJustifyContent)justifyContent alignItems:(ASStackLayoutAlignItems)alignItems flexWrap:(ASStackLayoutFlexWrap)flexWrap alignContent:(ASStackLayoutAlignContent)alignContent lineSpacing:(CGFloat)lineSpacing children:(NSArray<id<ASLayoutElement>> *)children
|
||||
{
|
||||
return [[self alloc] initWithDirection:direction spacing:spacing justifyContent:justifyContent alignItems:alignItems flexWrap:flexWrap alignContent:alignContent lineSpacing:lineSpacing children:children];
|
||||
}
|
||||
|
||||
+ (instancetype)verticalStackLayoutSpec
|
||||
@@ -60,7 +65,7 @@
|
||||
return stackLayoutSpec;
|
||||
}
|
||||
|
||||
- (instancetype)initWithDirection:(ASStackLayoutDirection)direction spacing:(CGFloat)spacing justifyContent:(ASStackLayoutJustifyContent)justifyContent alignItems:(ASStackLayoutAlignItems)alignItems flexWrap:(ASStackLayoutFlexWrap)flexWrap alignContent:(ASStackLayoutAlignContent)alignContent children:(NSArray *)children
|
||||
- (instancetype)initWithDirection:(ASStackLayoutDirection)direction spacing:(CGFloat)spacing justifyContent:(ASStackLayoutJustifyContent)justifyContent alignItems:(ASStackLayoutAlignItems)alignItems flexWrap:(ASStackLayoutFlexWrap)flexWrap alignContent:(ASStackLayoutAlignContent)alignContent lineSpacing:(CGFloat)lineSpacing children:(NSArray *)children
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
return nil;
|
||||
@@ -73,6 +78,7 @@
|
||||
_justifyContent = justifyContent;
|
||||
_flexWrap = flexWrap;
|
||||
_alignContent = alignContent;
|
||||
_lineSpacing = lineSpacing;
|
||||
|
||||
[self setChildren:children];
|
||||
return self;
|
||||
@@ -144,7 +150,7 @@
|
||||
return {child, style, style.size};
|
||||
});
|
||||
|
||||
const ASStackLayoutSpecStyle style = {.direction = _direction, .spacing = _spacing, .justifyContent = _justifyContent, .alignItems = _alignItems, .flexWrap = _flexWrap, .alignContent = _alignContent};
|
||||
const ASStackLayoutSpecStyle style = {.direction = _direction, .spacing = _spacing, .justifyContent = _justifyContent, .alignItems = _alignItems, .flexWrap = _flexWrap, .alignContent = _alignContent, .lineSpacing = _lineSpacing};
|
||||
|
||||
const auto unpositionedLayout = ASStackUnpositionedLayout::compute(stackChildren, style, constrainedSize, _concurrent);
|
||||
const auto positionedLayout = ASStackPositionedLayout::compute(unpositionedLayout, style, constrainedSize);
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef struct {
|
||||
ASStackLayoutAlignItems alignItems;
|
||||
ASStackLayoutFlexWrap flexWrap;
|
||||
ASStackLayoutAlignContent alignContent;
|
||||
CGFloat lineSpacing;
|
||||
} ASStackLayoutSpecStyle;
|
||||
|
||||
inline CGFloat stackDimension(const ASStackLayoutDirection direction, const CGSize size)
|
||||
|
||||
@@ -160,6 +160,7 @@ ASStackPositionedLayout ASStackPositionedLayout::compute(const ASStackUnposition
|
||||
const auto numOfLines = lines.size();
|
||||
const auto direction = style.direction;
|
||||
const auto alignContent = style.alignContent;
|
||||
const auto lineSpacing = style.lineSpacing;
|
||||
const auto justifyContent = style.justifyContent;
|
||||
const auto crossViolation = ASStackUnpositionedLayout::computeCrossViolation(layout.crossDimensionSum, style, sizeRange);
|
||||
CGFloat crossOffset;
|
||||
@@ -171,7 +172,7 @@ ASStackPositionedLayout ASStackPositionedLayout::compute(const ASStackUnposition
|
||||
BOOL first = YES;
|
||||
for (const auto &line : lines) {
|
||||
if (!first) {
|
||||
p = p + directionPoint(direction, 0, crossSpacing);
|
||||
p = p + directionPoint(direction, 0, crossSpacing + lineSpacing);
|
||||
}
|
||||
first = NO;
|
||||
|
||||
|
||||
@@ -113,9 +113,12 @@ static void dispatchApplyIfNeeded(size_t iterationCount, BOOL forced, void(^work
|
||||
|
||||
@param lines unpositioned lines
|
||||
*/
|
||||
static CGFloat computeLinesCrossDimensionSum(const std::vector<ASStackUnpositionedLine> &lines)
|
||||
static CGFloat computeLinesCrossDimensionSum(const std::vector<ASStackUnpositionedLine> &lines,
|
||||
const ASStackLayoutSpecStyle &style)
|
||||
{
|
||||
return std::accumulate(lines.begin(), lines.end(), 0.0,
|
||||
return std::accumulate(lines.begin(), lines.end(),
|
||||
// Start from default spacing between each line:
|
||||
lines.empty() ? 0 : style.lineSpacing * (lines.size() - 1),
|
||||
[&](CGFloat x, const ASStackUnpositionedLine &l) {
|
||||
return x + l.crossSize;
|
||||
});
|
||||
@@ -236,7 +239,7 @@ static void stretchLinesAlongCrossDimension(std::vector<ASStackUnpositionedLine>
|
||||
{
|
||||
ASDisplayNodeCAssertFalse(lines.empty());
|
||||
const std::size_t numOfLines = lines.size();
|
||||
const CGFloat violation = ASStackUnpositionedLayout::computeCrossViolation(computeLinesCrossDimensionSum(lines), style, sizeRange);
|
||||
const CGFloat violation = ASStackUnpositionedLayout::computeCrossViolation(computeLinesCrossDimensionSum(lines, style), style, sizeRange);
|
||||
// Don't stretch if the stack is single line, because the line's cross size was clamped against the stack's constrained size.
|
||||
const BOOL shouldStretchLines = (numOfLines > 1
|
||||
&& style.alignContent == ASStackLayoutAlignContentStretch
|
||||
@@ -648,7 +651,8 @@ static std::vector<ASStackUnpositionedLine> collectChildrenIntoLines(const std::
|
||||
for(auto it = items.begin(); it != items.end(); ++it) {
|
||||
const auto &item = *it;
|
||||
const CGFloat itemStackDimension = stackDimension(style.direction, item.layout.size);
|
||||
const BOOL negativeViolationIfAddItem = (ASStackUnpositionedLayout::computeStackViolation(lineStackDimensionSum + itemStackDimension, style, sizeRange) < 0);
|
||||
const CGFloat itemAndSpacingStackDimension = (lineItems.empty() ? 0.0 : style.spacing) + item.child.style.spacingBefore + itemStackDimension + item.child.style.spacingAfter;
|
||||
const BOOL negativeViolationIfAddItem = (ASStackUnpositionedLayout::computeStackViolation(lineStackDimensionSum + itemAndSpacingStackDimension, style, sizeRange) < 0);
|
||||
const BOOL breakCurrentLine = negativeViolationIfAddItem && !lineItems.empty();
|
||||
|
||||
if (breakCurrentLine) {
|
||||
@@ -658,7 +662,7 @@ static std::vector<ASStackUnpositionedLine> collectChildrenIntoLines(const std::
|
||||
}
|
||||
|
||||
lineItems.push_back(std::move(item));
|
||||
lineStackDimensionSum += itemStackDimension;
|
||||
lineStackDimensionSum += itemAndSpacingStackDimension;
|
||||
}
|
||||
|
||||
// Handle last line
|
||||
@@ -752,7 +756,7 @@ ASStackUnpositionedLayout ASStackUnpositionedLayout::compute(const std::vector<A
|
||||
}
|
||||
// Compute cross dimension sum of the stack.
|
||||
// This should be done before `lines` are moved to a new ASStackUnpositionedLayout struct (i.e `std::move(lines)`)
|
||||
CGFloat layoutCrossDimensionSum = computeLinesCrossDimensionSum(lines);
|
||||
CGFloat layoutCrossDimensionSum = computeLinesCrossDimensionSum(lines, style);
|
||||
|
||||
return {.lines = std::move(lines), .stackDimensionSum = layoutStackDimensionSum, .crossDimensionSum = layoutCrossDimensionSum};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user