[Layout] Treat flex factors as true factors (#2349)
* Treat flex factors as factors * Add snapshot tests * Address comments
@ -131,8 +131,8 @@ static const CGFloat kViolationEpsilon = 0.01;
|
||||
*/
|
||||
static std::function<CGFloat(const ASStackUnpositionedItem &)> flexFactorInViolationDirection(const CGFloat violation)
|
||||
{
|
||||
if (fabs(violation) < kViolationEpsilon) {
|
||||
return [](const ASStackUnpositionedItem &item) { return 0; };
|
||||
if (std::fabs(violation) < kViolationEpsilon) {
|
||||
return [](const ASStackUnpositionedItem &item) { return 0.0; };
|
||||
} else if (violation > 0) {
|
||||
return [](const ASStackUnpositionedItem &item) { return item.child.style.flexGrow; };
|
||||
} else {
|
||||
@ -140,9 +140,11 @@ static std::function<CGFloat(const ASStackUnpositionedItem &)> flexFactorInViola
|
||||
}
|
||||
}
|
||||
|
||||
static inline CGFloat scaledFlexShrinkFactor(const ASStackUnpositionedItem &item, const ASStackLayoutSpecStyle &style)
|
||||
static inline CGFloat scaledFlexShrinkFactor(const ASStackUnpositionedItem &item,
|
||||
const ASStackLayoutSpecStyle &style,
|
||||
const CGFloat flexFactorSum)
|
||||
{
|
||||
return stackDimension(style.direction, item.layout.size) * item.child.style.flexShrink;
|
||||
return stackDimension(style.direction, item.layout.size) * (item.child.style.flexShrink / flexFactorSum);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -150,20 +152,22 @@ static inline CGFloat scaledFlexShrinkFactor(const ASStackUnpositionedItem &item
|
||||
@param items The unpositioned items from the original unconstrained layout pass.
|
||||
@param style The layout style to be applied to all children.
|
||||
@param violation The amount that the stack layout violates its size range.
|
||||
@param flexFactorSum The sum of each item's flex factor as determined by the provided violation.
|
||||
@return A lambda capable of computing the flex shrink adjustment, if any, for a particular item.
|
||||
*/
|
||||
static std::function<CGFloat(const ASStackUnpositionedItem &, BOOL)> flexShrinkAdjustment(const std::vector<ASStackUnpositionedItem> &items,
|
||||
const ASStackLayoutSpecStyle &style,
|
||||
const CGFloat violation)
|
||||
static std::function<CGFloat(const ASStackUnpositionedItem &)> flexShrinkAdjustment(const std::vector<ASStackUnpositionedItem> &items,
|
||||
const ASStackLayoutSpecStyle &style,
|
||||
const CGFloat violation,
|
||||
const CGFloat flexFactorSum)
|
||||
{
|
||||
const CGFloat scaledFlexShrinkFactorSum = std::accumulate(items.begin(), items.end(), 0, [&](CGFloat x, const ASStackUnpositionedItem &item) {
|
||||
return x + scaledFlexShrinkFactor(item, style);
|
||||
const CGFloat scaledFlexShrinkFactorSum = std::accumulate(items.begin(), items.end(), 0.0, [&](CGFloat x, const ASStackUnpositionedItem &item) {
|
||||
return x + scaledFlexShrinkFactor(item, style, flexFactorSum);
|
||||
});
|
||||
return [style, scaledFlexShrinkFactorSum, violation](const ASStackUnpositionedItem &item, BOOL isFirstFlex) {
|
||||
const CGFloat scaledFlexShrinkFactorRatio = scaledFlexShrinkFactor(item, style) / scaledFlexShrinkFactorSum;
|
||||
return [style, scaledFlexShrinkFactorSum, violation, flexFactorSum](const ASStackUnpositionedItem &item) {
|
||||
const CGFloat scaledFlexShrinkFactorRatio = scaledFlexShrinkFactor(item, style, flexFactorSum) / scaledFlexShrinkFactorSum;
|
||||
// The item should shrink proportionally to the scaled flex shrink factor ratio computed above.
|
||||
// Unlike the flex grow adjustment the flex shrink adjustment needs to take the size of each item into account.
|
||||
return -fabs(scaledFlexShrinkFactorRatio * violation);
|
||||
return -std::fabs(scaledFlexShrinkFactorRatio * violation);
|
||||
};
|
||||
}
|
||||
|
||||
@ -174,17 +178,13 @@ static std::function<CGFloat(const ASStackUnpositionedItem &, BOOL)> flexShrinkA
|
||||
@param flexFactorSum The sum of each item's flex factor as determined by the provided violation.
|
||||
@return A lambda capable of computing the flex grow adjustment, if any, for a particular item.
|
||||
*/
|
||||
static std::function<CGFloat(const ASStackUnpositionedItem &, BOOL)> flexGrowAdjustment(const std::vector<ASStackUnpositionedItem> &items,
|
||||
const CGFloat violation,
|
||||
const CGFloat flexFactorSum)
|
||||
static std::function<CGFloat(const ASStackUnpositionedItem &)> flexGrowAdjustment(const std::vector<ASStackUnpositionedItem> &items,
|
||||
const CGFloat violation,
|
||||
const CGFloat flexFactorSum)
|
||||
{
|
||||
const CGFloat violationPerFlexFactor = floorf(violation / flexFactorSum);
|
||||
const CGFloat remainingViolation = violation - (violationPerFlexFactor * flexFactorSum);
|
||||
// To compute the flex grow adjustment distribute the violation proportionally based on each item's flex grow factor.
|
||||
// If there happens to be a violation remaining make sure it is allocated to the first flexible child.
|
||||
return [violationPerFlexFactor, remainingViolation](const ASStackUnpositionedItem &item, BOOL isFirstFlex) {
|
||||
// Only apply the remaining violation for the first flexible child that has a flex grow factor.
|
||||
return violationPerFlexFactor * item.child.style.flexGrow + (isFirstFlex && item.child.style.flexGrow > 0 ? remainingViolation : 0);
|
||||
return [violation, flexFactorSum](const ASStackUnpositionedItem &item) {
|
||||
return std::floor(violation * (item.child.style.flexGrow / flexFactorSum));
|
||||
};
|
||||
}
|
||||
|
||||
@ -196,15 +196,15 @@ static std::function<CGFloat(const ASStackUnpositionedItem &, BOOL)> flexGrowAdj
|
||||
@param flexFactorSum The sum of each item's flex factor as determined by the provided violation.
|
||||
@return A lambda capable of computing the flex adjustment for a particular item.
|
||||
*/
|
||||
static std::function<CGFloat(const ASStackUnpositionedItem &, BOOL)> flexAdjustmentInViolationDirection(const std::vector<ASStackUnpositionedItem> &items,
|
||||
const ASStackLayoutSpecStyle &style,
|
||||
const CGFloat violation,
|
||||
const CGFloat flexFactorSum)
|
||||
static std::function<CGFloat(const ASStackUnpositionedItem &)> flexAdjustmentInViolationDirection(const std::vector<ASStackUnpositionedItem> &items,
|
||||
const ASStackLayoutSpecStyle &style,
|
||||
const CGFloat violation,
|
||||
const CGFloat flexFactorSum)
|
||||
{
|
||||
if (violation > 0) {
|
||||
return flexGrowAdjustment(items, violation, flexFactorSum);
|
||||
} else {
|
||||
return flexShrinkAdjustment(items, style, violation);
|
||||
return flexShrinkAdjustment(items, style, violation, flexFactorSum);
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,7 +352,7 @@ static void flexChildrenAlongStackDimension(std::vector<ASStackUnpositionedItem>
|
||||
std::function<CGFloat(const ASStackUnpositionedItem &)> flexFactor = flexFactorInViolationDirection(violation);
|
||||
// The flex factor sum is needed to determine if flexing is necessary.
|
||||
// This value is also needed if the violation is positive and flexible children need to grow, so keep it around.
|
||||
const CGFloat flexFactorSum = std::accumulate(items.begin(), items.end(), 0, [&](CGFloat x, const ASStackUnpositionedItem &item) {
|
||||
const CGFloat flexFactorSum = std::accumulate(items.begin(), items.end(), 0.0, [&](CGFloat x, const ASStackUnpositionedItem &item) {
|
||||
return x + flexFactor(item);
|
||||
});
|
||||
// If no children are able to flex then there is nothing left to do. Bail.
|
||||
@ -363,17 +363,23 @@ static void flexChildrenAlongStackDimension(std::vector<ASStackUnpositionedItem>
|
||||
}
|
||||
return;
|
||||
}
|
||||
std::function<CGFloat(const ASStackUnpositionedItem &, BOOL)> flexAdjustment = flexAdjustmentInViolationDirection(items,
|
||||
style,
|
||||
violation,
|
||||
flexFactorSum);
|
||||
std::function<CGFloat(const ASStackUnpositionedItem &)> flexAdjustment = flexAdjustmentInViolationDirection(items,
|
||||
style,
|
||||
violation,
|
||||
flexFactorSum);
|
||||
|
||||
// Compute any remaining violation to the first flexible child.
|
||||
const CGFloat remainingViolation = std::accumulate(items.begin(), items.end(), violation, [&](CGFloat x, const ASStackUnpositionedItem &item) {
|
||||
return x - flexAdjustment(item);
|
||||
});
|
||||
BOOL isFirstFlex = YES;
|
||||
for (ASStackUnpositionedItem &item : items) {
|
||||
const CGFloat currentFlexAdjustment = flexAdjustment(item, isFirstFlex);
|
||||
const CGFloat currentFlexAdjustment = flexAdjustment(item);
|
||||
// Children are consider inflexible if they do not need to make a flex adjustment.
|
||||
if (currentFlexAdjustment != 0) {
|
||||
const CGFloat originalStackSize = stackDimension(style.direction, item.layout.size);
|
||||
const CGFloat flexedStackSize = originalStackSize + currentFlexAdjustment;
|
||||
// Only apply the remaining violation for the first flexible child that has a flex grow factor.
|
||||
const CGFloat flexedStackSize = originalStackSize + currentFlexAdjustment + (isFirstFlex && item.child.style.flexGrow > 0 ? remainingViolation : 0);
|
||||
item.layout = crossChildLayout(item.child,
|
||||
style,
|
||||
MAX(flexedStackSize, 0),
|
||||
|
||||
@ -21,6 +21,15 @@
|
||||
|
||||
@implementation ASStackLayoutSpecSnapshotTests
|
||||
|
||||
#pragma mark - XCTestCase
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
|
||||
self.recordMode = NO;
|
||||
}
|
||||
|
||||
#pragma mark - Utility methods
|
||||
|
||||
static NSArray<ASDisplayNode *> *defaultSubnodes()
|
||||
@ -597,13 +606,13 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node)
|
||||
[self testLayoutSpec:layoutSpec sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testPositiveViolationIsDistributedEquallyAmongFlexibleChildren
|
||||
- (void)testPositiveViolationIsDistributedEqually
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
||||
|
||||
NSArray<ASDisplayNode *> *subnodes = defaultSubnodesWithSameSize({50, 50}, 0);
|
||||
subnodes[0].style.flexGrow = 0;
|
||||
subnodes[2].style.flexGrow = 0;
|
||||
subnodes[0].style.flexGrow = 1;
|
||||
subnodes[2].style.flexGrow = 1;
|
||||
|
||||
// In this scenario a width of 350 results in a positive violation of 200.
|
||||
// Due to each flexible subnode specifying a flex grow factor of 1 the violation will be distributed evenly.
|
||||
@ -611,7 +620,21 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node)
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testPositiveViolationIsDistributedProportionallyAmongFlexibleChildren
|
||||
- (void)testPositiveViolationIsDistributedEquallyWithArbitraryFloats
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
||||
|
||||
NSArray<ASDisplayNode *> *subnodes = defaultSubnodesWithSameSize({50, 50}, 0);
|
||||
subnodes[0].style.flexGrow = 0.5;
|
||||
subnodes[2].style.flexGrow = 0.5;
|
||||
|
||||
// In this scenario a width of 350 results in a positive violation of 200.
|
||||
// Due to each flexible child component specifying a flex grow factor of 0.5 the violation will be distributed evenly.
|
||||
static ASSizeRange kSize = {{350, 350}, {350, 350}};
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testPositiveViolationIsDistributedProportionally
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical};
|
||||
|
||||
@ -627,7 +650,23 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node)
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testPositiveViolationIsDistributedEquallyAmongGrowingAndShrinkingFlexibleChildren
|
||||
- (void)testPositiveViolationIsDistributedProportionallyWithArbitraryFloats
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical};
|
||||
|
||||
NSArray<ASDisplayNode *> *subnodes = defaultSubnodesWithSameSize({50, 50}, 0);
|
||||
subnodes[0].style.flexGrow = 0.25;
|
||||
subnodes[1].style.flexGrow = 0.50;
|
||||
subnodes[2].style.flexGrow = 0.25;
|
||||
|
||||
// In this scenario a width of 350 results in a positive violation of 200.
|
||||
// The first and third child components specify a flex grow factor of 0.25 and will flex by 50.
|
||||
// The second child component specifies a flex grow factor of 0.25 and will flex by 100.
|
||||
static ASSizeRange kSize = {{350, 350}, {350, 350}};
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testPositiveViolationIsDistributedEquallyAmongMixedChildren
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
||||
|
||||
@ -647,7 +686,27 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node)
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testPositiveViolationIsDistributedProportionallyAmongGrowingAndShrinkingFlexibleChildren
|
||||
- (void)testPositiveViolationIsDistributedEquallyAmongMixedChildrenWithArbitraryFloats
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
||||
|
||||
const CGSize kSubnodeSize = {50, 50};
|
||||
NSArray<ASDisplayNode *> *subnodes = defaultSubnodesWithSameSize(kSubnodeSize, 0);
|
||||
subnodes = [subnodes arrayByAddingObject:ASDisplayNodeWithBackgroundColor([UIColor yellowColor], kSubnodeSize)];
|
||||
|
||||
subnodes[0].style.flexShrink = 1.0;
|
||||
subnodes[1].style.flexGrow = 0.5;
|
||||
subnodes[2].style.flexShrink = 0.0;
|
||||
subnodes[3].style.flexGrow = 0.5;
|
||||
|
||||
// In this scenario a width of 400 results in a positive violation of 200.
|
||||
// The first and third child components specify a flex shrink factor of 1 and 0, respectively. They won't flex.
|
||||
// The second and fourth child components specify a flex grow factor of 0.5 and will flex by 100.
|
||||
static ASSizeRange kSize = {{400, 400}, {400, 400}};
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testPositiveViolationIsDistributedProportionallyAmongMixedChildren
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical};
|
||||
|
||||
@ -668,6 +727,27 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node)
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testPositiveViolationIsDistributedProportionallyAmongMixedChildrenWithArbitraryFloats
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical};
|
||||
|
||||
const CGSize kSubnodeSize = {50, 50};
|
||||
NSArray<ASDisplayNode *> *subnodes = defaultSubnodesWithSameSize(kSubnodeSize, 0);
|
||||
subnodes = [subnodes arrayByAddingObject:ASDisplayNodeWithBackgroundColor([UIColor yellowColor], kSubnodeSize)];
|
||||
|
||||
subnodes[0].style.flexShrink = 1.0;
|
||||
subnodes[1].style.flexGrow = 0.75;
|
||||
subnodes[2].style.flexShrink = 0.0;
|
||||
subnodes[3].style.flexGrow = 0.25;
|
||||
|
||||
// In this scenario a width of 400 results in a positive violation of 200.
|
||||
// The first and third child components specify a flex shrink factor of 1 and 0, respectively. They won't flex.
|
||||
// The second child component specifies a flex grow factor of 0.75 and will flex by 150.
|
||||
// The fourth child component specifies a flex grow factor of 0.25 and will flex by 50.
|
||||
static ASSizeRange kSize = {{400, 400}, {400, 400}};
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testRemainingViolationIsAppliedProperlyToFirstFlexibleChild
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical};
|
||||
@ -688,7 +768,27 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node)
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNegativeViolationIsDistributedProportionallyBasedOnSizeAmongFlexibleChildren
|
||||
- (void)testRemainingViolationIsAppliedProperlyToFirstFlexibleChildWithArbitraryFloats
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical};
|
||||
|
||||
NSArray<ASDisplayNode *> *subnodes = @[
|
||||
ASDisplayNodeWithBackgroundColor([UIColor greenColor], {50, 25}),
|
||||
ASDisplayNodeWithBackgroundColor([UIColor blueColor], {50, 0}),
|
||||
ASDisplayNodeWithBackgroundColor([UIColor redColor], {50, 100})
|
||||
];
|
||||
|
||||
subnodes[0].style.flexGrow = 0.0;
|
||||
subnodes[1].style.flexGrow = 0.5;
|
||||
subnodes[2].style.flexGrow = 0.5;
|
||||
|
||||
// In this scenario a width of 300 results in a positive violation of 175.
|
||||
// The second and third child components specify a flex grow factor of 0.5 and will flex by 88 and 87, respectively.
|
||||
static ASSizeRange kSize = {{300, 300}, {300, 300}};
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNegativeViolationIsDistributedBasedOnSize
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
||||
|
||||
@ -708,7 +808,27 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node)
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNegativeViolationIsDistributedProportionallyBasedOnSizeAndFlexFactorAmongFlexibleChildren
|
||||
- (void)testNegativeViolationIsDistributedBasedOnSizeWithArbitraryFloats
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
||||
|
||||
NSArray<ASDisplayNode *> *subnodes = @[
|
||||
ASDisplayNodeWithBackgroundColor([UIColor greenColor], {300, 50}),
|
||||
ASDisplayNodeWithBackgroundColor([UIColor blueColor], {100, 50}),
|
||||
ASDisplayNodeWithBackgroundColor([UIColor redColor], {200, 50})
|
||||
];
|
||||
|
||||
subnodes[0].style.flexShrink = 0.5;
|
||||
subnodes[1].style.flexShrink = 0.0;
|
||||
subnodes[2].style.flexShrink = 0.5;
|
||||
|
||||
// In this scenario a width of 400 results in a negative violation of 200.
|
||||
// The first and third child components specify a flex shrink factor of 0.5 and will flex by -120 and -80, respectively.
|
||||
static ASSizeRange kSize = {{400, 400}, {400, 400}};
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNegativeViolationIsDistributedBasedOnSizeAndFlexFactor
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical};
|
||||
|
||||
@ -729,7 +849,28 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node)
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNegativeViolationIsDistributedProportionallyBasedOnSizeAmongGrowingAndShrinkingFlexibleChildren
|
||||
- (void)testNegativeViolationIsDistributedBasedOnSizeAndFlexFactorWithArbitraryFloats
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical};
|
||||
|
||||
NSArray<ASDisplayNode *> *subnodes = @[
|
||||
ASDisplayNodeWithBackgroundColor([UIColor greenColor], {50, 300}),
|
||||
ASDisplayNodeWithBackgroundColor([UIColor blueColor], {50, 100}),
|
||||
ASDisplayNodeWithBackgroundColor([UIColor redColor], {50, 200})
|
||||
];
|
||||
|
||||
subnodes[0].style.flexShrink = 0.4;
|
||||
subnodes[1].style.flexShrink = 0.2;
|
||||
subnodes[2].style.flexShrink = 0.4;
|
||||
|
||||
// In this scenario a width of 400 results in a negative violation of 200.
|
||||
// The first and third child components specify a flex shrink factor of 0.4 and will flex by -109 and -72, respectively.
|
||||
// The second child component specifies a flex shrink factor of 0.2 and will flex by -18.
|
||||
static ASSizeRange kSize = {{400, 400}, {400, 400}};
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNegativeViolationIsDistributedBasedOnSizeAmongMixedChildrenChildren
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
||||
|
||||
@ -749,7 +890,27 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node)
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNegativeViolationIsDistributedProportionallyBasedOnSizeAndFlexFactorAmongGrowingAndShrinkingFlexibleChildren
|
||||
- (void)testNegativeViolationIsDistributedBasedOnSizeAmongMixedChildrenWithArbitraryFloats
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
||||
|
||||
const CGSize kSubnodeSize = {150, 50};
|
||||
NSArray<ASDisplayNode *> *subnodes = defaultSubnodesWithSameSize(kSubnodeSize, 0);
|
||||
subnodes = [subnodes arrayByAddingObject:ASDisplayNodeWithBackgroundColor([UIColor yellowColor], kSubnodeSize)];
|
||||
|
||||
subnodes[0].style.flexGrow = 1.0;
|
||||
subnodes[1].style.flexShrink = 0.5;
|
||||
subnodes[2].style.flexGrow = 0.0;
|
||||
subnodes[3].style.flexShrink = 0.5;
|
||||
|
||||
// In this scenario a width of 400 results in a negative violation of 200.
|
||||
// The first and third child components specify a flex grow factor of 1 and 0, respectively. They won't flex.
|
||||
// The second and fourth child components specify a flex shrink factor of 0.5 and will flex by -100.
|
||||
static ASSizeRange kSize = {{400, 400}, {400, 400}};
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNegativeViolationIsDistributedBasedOnSizeAndFlexFactorAmongMixedChildren
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical};
|
||||
|
||||
@ -773,7 +934,31 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node)
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNegativeViolationIsDistributedProportionallyBasedOnSizeAndFlexFactorDoesNotShrinkToZeroWidth
|
||||
- (void)testNegativeViolationIsDistributedBasedOnSizeAndFlexFactorAmongMixedChildrenArbitraryFloats
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionVertical};
|
||||
|
||||
NSArray<ASDisplayNode *> *subnodes = @[
|
||||
ASDisplayNodeWithBackgroundColor([UIColor greenColor], {50, 150}),
|
||||
ASDisplayNodeWithBackgroundColor([UIColor blueColor], {50, 100}),
|
||||
ASDisplayNodeWithBackgroundColor([UIColor redColor], {50, 150}),
|
||||
ASDisplayNodeWithBackgroundColor([UIColor yellowColor], {50, 200})
|
||||
];
|
||||
|
||||
subnodes[0].style.flexGrow = 1.0;
|
||||
subnodes[1].style.flexShrink = 0.25;
|
||||
subnodes[2].style.flexGrow = 0.0;
|
||||
subnodes[3].style.flexShrink = 0.75;
|
||||
|
||||
// In this scenario a width of 400 results in a negative violation of 200.
|
||||
// The first and third child components specify a flex grow factor of 1 and 0, respectively. They won't flex.
|
||||
// The second child component specifies a flex shrink factor of 0.25 and will flex by -28.
|
||||
// The fourth child component specifies a flex shrink factor of 0.75 and will flex by -171.
|
||||
static ASSizeRange kSize = {{400, 400}, {400, 400}};
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNegativeViolationIsDistributedBasedOnSizeAndFlexFactorDoesNotShrinkToZero
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
||||
|
||||
@ -794,6 +979,27 @@ static void setCGSizeToNode(CGSize size, ASDisplayNode *node)
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNegativeViolationIsDistributedBasedOnSizeAndFlexFactorDoesNotShrinkToZeroWithArbitraryFloats
|
||||
{
|
||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
||||
|
||||
NSArray<ASDisplayNode *> *subnodes = @[
|
||||
ASDisplayNodeWithBackgroundColor([UIColor greenColor], {300, 50}),
|
||||
ASDisplayNodeWithBackgroundColor([UIColor blueColor], {100, 50}),
|
||||
ASDisplayNodeWithBackgroundColor([UIColor redColor], {200, 50})
|
||||
];
|
||||
|
||||
subnodes[0].style.flexShrink = 0.25;
|
||||
subnodes[1].style.flexShrink = 0.50;
|
||||
subnodes[2].style.flexShrink = 0.25;
|
||||
|
||||
// In this scenario a width of 400 results in a negative violation of 200.
|
||||
// The first and third child components specify a flex shrink factor of 0.25 and will flex by 50.
|
||||
// The second child component specifies a flex shrink factor of 0.50 and will flex by -57. It will have a width of 43.
|
||||
static ASSizeRange kSize = {{400, 400}, {400, 400}};
|
||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||
}
|
||||
|
||||
- (void)testNestedStackLayoutStretchDoesNotViolateWidth
|
||||
{
|
||||
ASStackLayoutSpec *stackLayoutSpec = [[ASStackLayoutSpec alloc] init]; // Default direction is horizontal
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |