Skip to content

Commit

Permalink
[ASStackLayoutSpec] Flex wrap fix and lineSpacing property (TextureGr…
Browse files Browse the repository at this point in the history
…oup#472)

* ASStackUnpositionedLayout: Take spacing into account when laying out a wrapped stack.

* ASStackLayoutSpec: Add the lineSpacing property.

* Update CHANGELOG.md.
  • Loading branch information
flovouin authored and bernieperez committed Apr 25, 2018
1 parent fa21c75 commit ec83812
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 12 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
21 changes: 21 additions & 0 deletions Source/Layout/ASStackLayoutSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
**/
Expand Down
16 changes: 11 additions & 5 deletions Source/Layout/ASStackLayoutSpec.mm
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,22 @@ @implementation ASStackLayoutSpec

- (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
Expand All @@ -60,7 +65,7 @@ + (instancetype)horizontalStackLayoutSpec
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;
Expand All @@ -73,6 +78,7 @@ - (instancetype)initWithDirection:(ASStackLayoutDirection)direction spacing:(CGF
_justifyContent = justifyContent;
_flexWrap = flexWrap;
_alignContent = alignContent;
_lineSpacing = lineSpacing;

[self setChildren:children];
return self;
Expand Down Expand Up @@ -144,7 +150,7 @@ - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
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);
Expand Down
1 change: 1 addition & 0 deletions Source/Private/Layout/ASStackLayoutSpecUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ typedef struct {
ASStackLayoutAlignItems alignItems;
ASStackLayoutFlexWrap flexWrap;
ASStackLayoutAlignContent alignContent;
CGFloat lineSpacing;
} ASStackLayoutSpecStyle;

inline CGFloat stackDimension(const ASStackLayoutDirection direction, const CGSize size)
Expand Down
3 changes: 2 additions & 1 deletion Source/Private/Layout/ASStackPositionedLayout.mm
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ static void positionItemsInLine(const ASStackUnpositionedLine &line,
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;
Expand All @@ -171,7 +172,7 @@ static void positionItemsInLine(const ASStackUnpositionedLine &line,
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;

Expand Down
16 changes: 10 additions & 6 deletions Source/Private/Layout/ASStackUnpositionedLayout.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -648,7 +651,8 @@ static void flexLinesAlongStackDimension(std::vector<ASStackUnpositionedLine> &l
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) {
Expand All @@ -658,7 +662,7 @@ static void flexLinesAlongStackDimension(std::vector<ASStackUnpositionedLine> &l
}

lineItems.push_back(std::move(item));
lineStackDimensionSum += itemStackDimension;
lineStackDimensionSum += itemAndSpacingStackDimension;
}

// Handle last line
Expand Down Expand Up @@ -752,7 +756,7 @@ static void layoutItemsAlongUnconstrainedStackDimension(std::vector<ASStackLayou
}
// 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};
}

0 comments on commit ec83812

Please sign in to comment.