mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
[Layout] Treat flex factors as true factors (#2349)
* Treat flex factors as factors * Add snapshot tests * Address comments
This commit is contained in:
committed by
Adlai Holler
parent
124234fef8
commit
94f958c4a3
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user