Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ASStackLayoutSpec] Flex wrap fix and lineSpacing property #472

Merged
merged 3 commits into from
Aug 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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};
}