iOS: DoricLayout add measureState

This commit is contained in:
pengfei.zhou 2022-08-24 16:09:31 +08:00 committed by osborn
parent 2ba4323c7c
commit c8365973f0

View File

@ -104,6 +104,13 @@ typedef NS_ENUM(NSInteger, DoricMeasureSpecMode) {
typedef struct DoricMeasureSpec DoricMeasureSpec; typedef struct DoricMeasureSpec DoricMeasureSpec;
struct DoricSizeAndState {
NSUInteger state;
CGFloat size;
};
typedef struct DoricSizeAndState DoricSizeAndState;
DoricMeasureSpec DoricMeasureSpecMake(DoricMeasureSpecMode mode, CGFloat size) { DoricMeasureSpec DoricMeasureSpecMake(DoricMeasureSpecMode mode, CGFloat size) {
DoricMeasureSpec spec; DoricMeasureSpec spec;
spec.mode = mode; spec.mode = mode;
@ -111,7 +118,18 @@ DoricMeasureSpec DoricMeasureSpecMake(DoricMeasureSpecMode mode, CGFloat size) {
return spec; return spec;
} }
NSUInteger DORIC_MEASURED_STATE_MASK = 0x11;
NSUInteger DORIC_MEASURED_HEIGHT_STATE_SHIFT = 8;
NSUInteger DORIC_MEASURED_STATE_TOO_SMALL = 0x01;
@interface DoricLayout () @interface DoricLayout ()
/**
* width-height
* 0xff--ff
* */
@property(nonatomic, assign) NSUInteger measuredState;
@end @end
@implementation DoricLayout @implementation DoricLayout
@ -123,6 +141,7 @@ - (instancetype)init {
_maxHeight = CGFLOAT_MAX; _maxHeight = CGFLOAT_MAX;
_minWidth = -1; _minWidth = -1;
_minHeight = -1; _minHeight = -1;
_measuredState = 0;
} }
return self; return self;
} }
@ -278,42 +297,50 @@ - (void)measureChild:(DoricLayout *)child
heightSpec:(DoricMeasureSpec)heightSpec heightSpec:(DoricMeasureSpec)heightSpec
usedHeight:(CGFloat)usedHeight { usedHeight:(CGFloat)usedHeight {
DoricMeasureSpec childWidthSpec = [self getChildMeasureSpec:widthSpec DoricMeasureSpec childWidthSpec =
padding:self.paddingLeft + self.paddingRight [self getChildMeasureSpec:widthSpec
+ child.marginLeft + child.marginRight padding:self.paddingLeft + self.paddingRight
+ usedWidth + child.marginLeft + child.marginRight
childLayoutSpec:child.widthSpec + usedWidth
childSize:child.width]; childLayoutSpec:child.widthSpec
childSize:child.width];
DoricMeasureSpec childHeightSpec = [self getChildMeasureSpec:heightSpec DoricMeasureSpec childHeightSpec =
padding:self.paddingTop + self.paddingBottom [self getChildMeasureSpec:heightSpec
+ child.marginTop + child.marginBottom padding:self.paddingTop + self.paddingBottom
+ usedHeight + child.marginTop + child.marginBottom
childLayoutSpec:child.heightSpec + usedHeight
childSize:child.height]; childLayoutSpec:child.heightSpec
childSize:child.height];
[child measureWidth:childWidthSpec height:childHeightSpec]; [child measureWidth:childWidthSpec height:childHeightSpec];
} }
- (CGFloat)resolveSize:(CGFloat)size spec:(DoricMeasureSpec)measureSpec {
- (DoricSizeAndState)resolveSizeAndState:(CGFloat)size
spec:(DoricMeasureSpec)measureSpec
childMeasuredState:(NSUInteger)state {
DoricSizeAndState result;
DoricMeasureSpecMode specMode = measureSpec.mode; DoricMeasureSpecMode specMode = measureSpec.mode;
CGFloat specSize = measureSpec.size; CGFloat specSize = measureSpec.size;
CGFloat result; result.state = 0;
switch (specMode) { switch (specMode) {
case DoricMeasureAtMost: case DoricMeasureAtMost:
if (specSize < size) { if (specSize < size) {
result = specSize; result.size = specSize;
result.state = DORIC_MEASURED_STATE_TOO_SMALL;
} else { } else {
result = size; result.size = size;
} }
break; break;
case DoricMeasureExactly: case DoricMeasureExactly:
result = specSize; result.size = specSize;
break; break;
case DoricMeasureUnspecified: case DoricMeasureUnspecified:
default: default:
result = size; result.size = size;
break; break;
} }
result.state = result.state | (state & DORIC_MEASURED_STATE_MASK);
return result; return result;
} }
@ -334,7 +361,8 @@ - (CGFloat)getDefaultSize:(CGFloat)size spec:(DoricMeasureSpec)measureSpec {
} }
- (void)forceUniformWidth:(DoricMeasureSpec)heightMeasureSpec { - (void)forceUniformWidth:(DoricMeasureSpec)heightMeasureSpec {
DoricMeasureSpec uniformMeasureSpec = DoricMeasureSpecMake(DoricMeasureExactly, self.measuredWidth); DoricMeasureSpec uniformMeasureSpec = DoricMeasureSpecMake(DoricMeasureExactly,
self.measuredWidth);
for (__kindof UIView *subview in self.view.subviews) { for (__kindof UIView *subview in self.view.subviews) {
DoricLayout *childLayout = subview.doricLayout; DoricLayout *childLayout = subview.doricLayout;
if (childLayout.disabled) { if (childLayout.disabled) {
@ -366,7 +394,8 @@ - (void)forceUniformHeight:(DoricMeasureSpec)widthMeasureSpec {
// Pretend that the linear layout has an exact size. This is the measured height of // Pretend that the linear layout has an exact size. This is the measured height of
// ourselves. The measured height should be the max height of the children, changed // ourselves. The measured height should be the max height of the children, changed
// to accommodate the heightMeasureSpec from the parent // to accommodate the heightMeasureSpec from the parent
DoricMeasureSpec uniformMeasureSpec = DoricMeasureSpecMake(DoricMeasureExactly, self.measuredHeight); DoricMeasureSpec uniformMeasureSpec
= DoricMeasureSpecMake(DoricMeasureExactly, self.measuredHeight);
for (__kindof UIView *subview in self.view.subviews) { for (__kindof UIView *subview in self.view.subviews) {
DoricLayout *childLayout = subview.doricLayout; DoricLayout *childLayout = subview.doricLayout;
if (childLayout.disabled) { if (childLayout.disabled) {
@ -415,7 +444,8 @@ - (void)measureWidth:(DoricMeasureSpec)widthSpec height:(DoricMeasureSpec)height
} }
} }
- (void)verticalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMeasureSpec)heightMeasureSpec { - (void)verticalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec
height:(DoricMeasureSpec)heightMeasureSpec {
CGFloat maxWidth = 0, totalLength = 0; CGFloat maxWidth = 0, totalLength = 0;
NSUInteger totalWeight = 0; NSUInteger totalWeight = 0;
BOOL hadExtraSpace = NO; BOOL hadExtraSpace = NO;
@ -429,7 +459,7 @@ - (void)verticalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMea
CGFloat weightedMaxWidth = 0; CGFloat weightedMaxWidth = 0;
CGFloat alternativeMaxWidth = 0; CGFloat alternativeMaxWidth = 0;
NSUInteger childState = 0;
// See how tall everyone is. Also remember max width. // See how tall everyone is. Also remember max width.
for (__kindof UIView *subview in self.view.subviews) { for (__kindof UIView *subview in self.view.subviews) {
@ -448,7 +478,8 @@ - (void)verticalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMea
// Optimization: don't bother measuring children who are going to use // Optimization: don't bother measuring children who are going to use
// leftover space. These views will get measured again down below if // leftover space. These views will get measured again down below if
// there is any leftover space. // there is any leftover space.
totalLength = MAX(totalLength, totalLength + childLayout.marginTop + childLayout.marginBottom); totalLength = MAX(totalLength, totalLength
+childLayout.marginTop + childLayout.marginBottom);
skippedMeasure = YES; skippedMeasure = YES;
} else { } else {
CGFloat oldHeight = CGFLOAT_MIN; CGFloat oldHeight = CGFLOAT_MIN;
@ -497,15 +528,19 @@ - (void)verticalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMea
CGFloat measuredWidth = childLayout.measuredWidth + margin; CGFloat measuredWidth = childLayout.measuredWidth + margin;
maxWidth = MAX(maxWidth, measuredWidth); maxWidth = MAX(maxWidth, measuredWidth);
childState = childState | childLayout.measuredState;
allFillParent = allFillParent && childLayout.widthSpec == DoricLayoutMost; allFillParent = allFillParent && childLayout.widthSpec == DoricLayoutMost;
if (childLayout.weight > 0) { if (childLayout.weight > 0) {
/* /*
* Widths of weighted Views are bogus if we end up * Widths of weighted Views are bogus if we end up
* remeasuring, so keep them separate. * remeasuring, so keep them separate.
*/ */
weightedMaxWidth = MAX(weightedMaxWidth, matchWidthLocally ? margin : measuredWidth); weightedMaxWidth
= MAX(weightedMaxWidth, matchWidthLocally ? margin : measuredWidth);
} else { } else {
alternativeMaxWidth = MAX(alternativeMaxWidth, matchWidthLocally ? margin : measuredWidth); alternativeMaxWidth
= MAX(alternativeMaxWidth, matchWidthLocally ? margin : measuredWidth);
} }
} }
@ -521,7 +556,10 @@ - (void)verticalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMea
heightSize = MAX(heightSize, self.minHeight); heightSize = MAX(heightSize, self.minHeight);
// Reconcile our calculated size with the heightMeasureSpec // Reconcile our calculated size with the heightMeasureSpec
heightSize = [self resolveSize:heightSize spec:heightMeasureSpec]; DoricSizeAndState heightSizeAndState = [self resolveSizeAndState:heightSize
spec:heightMeasureSpec
childMeasuredState:0];
heightSize = heightSizeAndState.size;
// Either expand children with weight to take up available space or // Either expand children with weight to take up available space or
// shrink them if they extend beyond our current bounds. If we skipped // shrink them if they extend beyond our current bounds. If we skipped
@ -541,11 +579,13 @@ - (void)verticalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMea
CGFloat share = childExtra * delta / weightSum; CGFloat share = childExtra * delta / weightSum;
weightSum -= childExtra; weightSum -= childExtra;
delta -= share; delta -= share;
DoricMeasureSpec childWidthMeasureSpec = [self getChildMeasureSpec:widthMeasureSpec DoricMeasureSpec childWidthMeasureSpec =
padding:self.paddingLeft + self.paddingRight [self getChildMeasureSpec:widthMeasureSpec
+ childLayout.marginLeft + childLayout.marginRight padding:self.paddingLeft + self.paddingRight
childLayoutSpec:childLayout.widthSpec + childLayout.marginLeft
childSize:childLayout.width]; + childLayout.marginRight
childLayoutSpec:childLayout.widthSpec
childSize:childLayout.width];
// TODO: Use a field like lp.isMeasured to figure out if this // TODO: Use a field like lp.isMeasured to figure out if this
// child has been previously measured // child has been previously measured
if (!(childLayout.heightSpec == DoricLayoutJust && childLayout.height == 0) if (!(childLayout.heightSpec == DoricLayoutJust && childLayout.height == 0)
@ -557,13 +597,19 @@ - (void)verticalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMea
childHeight = 0; childHeight = 0;
} }
[childLayout measureWidth:childWidthMeasureSpec [childLayout measureWidth:childWidthMeasureSpec
height:DoricMeasureSpecMake(DoricMeasureExactly, childHeight)]; height:DoricMeasureSpecMake(DoricMeasureExactly,
childHeight)];
} else { } else {
// child was skipped in the loop above. // child was skipped in the loop above.
// Measure for this first time here // Measure for this first time here
[childLayout measureWidth:childWidthMeasureSpec [childLayout measureWidth:childWidthMeasureSpec
height:DoricMeasureSpecMake(DoricMeasureExactly, share > 0 ? share : 0)]; height:DoricMeasureSpecMake(DoricMeasureExactly,
share > 0 ? share : 0)];
} }
// Child may now not fit in vertical dimension.
childState = childState | (childLayout.measuredState
& (DORIC_MEASURED_STATE_MASK >> DORIC_MEASURED_HEIGHT_STATE_SHIFT));
} }
@ -571,9 +617,11 @@ - (void)verticalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMea
CGFloat measuredWidth = childLayout.measuredWidth + margin; CGFloat measuredWidth = childLayout.measuredWidth + margin;
maxWidth = MAX(maxWidth, measuredWidth); maxWidth = MAX(maxWidth, measuredWidth);
BOOL matchWidthLocally = widthMode != DoricMeasureExactly && childLayout.widthSpec == DoricLayoutMost; BOOL matchWidthLocally = widthMode != DoricMeasureExactly
&& childLayout.widthSpec == DoricLayoutMost;
alternativeMaxWidth = MAX(alternativeMaxWidth, matchWidthLocally ? margin : measuredWidth); alternativeMaxWidth = MAX(alternativeMaxWidth,
matchWidthLocally ? margin : measuredWidth);
allFillParent = allFillParent && childLayout.widthSpec == DoricLayoutMost; allFillParent = allFillParent && childLayout.widthSpec == DoricLayoutMost;
@ -598,9 +646,16 @@ - (void)verticalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMea
// Check against our minimum width // Check against our minimum width
maxWidth = MAX(maxWidth, self.minWidth); maxWidth = MAX(maxWidth, self.minWidth);
self.measuredWidth = [self resolveSize:maxWidth spec:widthMeasureSpec]; DoricSizeAndState widthSizeAndState = [self resolveSizeAndState:maxWidth
spec:widthMeasureSpec
childMeasuredState:childState];
self.measuredWidth = widthSizeAndState.size;
self.measuredHeight = heightSize; self.measuredHeight = heightSize;
self.measuredState = (widthSizeAndState.state
<< DORIC_MEASURED_HEIGHT_STATE_SHIFT) | heightSizeAndState.state;
if (matchWidth) { if (matchWidth) {
[self forceUniformWidth:heightMeasureSpec]; [self forceUniformWidth:heightMeasureSpec];
} }
@ -608,11 +663,11 @@ - (void)verticalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMea
} }
- (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMeasureSpec)heightMeasureSpec { - (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec
height:(DoricMeasureSpec)heightMeasureSpec {
CGFloat maxHeight = 0, totalLength = 0; CGFloat maxHeight = 0, totalLength = 0;
NSUInteger totalWeight = 0; NSUInteger totalWeight = 0;
BOOL hadExtraSpace = NO; BOOL hadExtraSpace = NO;
BOOL existsContent = NO;
DoricMeasureSpecMode widthMode = widthMeasureSpec.mode; DoricMeasureSpecMode widthMode = widthMeasureSpec.mode;
DoricMeasureSpecMode heightMode = heightMeasureSpec.mode; DoricMeasureSpecMode heightMode = heightMeasureSpec.mode;
@ -624,6 +679,9 @@ - (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricM
CGFloat weightedMaxHeight = 0; CGFloat weightedMaxHeight = 0;
CGFloat alternativeMaxHeight = 0; CGFloat alternativeMaxHeight = 0;
BOOL isExactly = widthMode == DoricMeasureExactly; BOOL isExactly = widthMode == DoricMeasureExactly;
NSUInteger childState = 0;
// See how wide everyone is. Also remember max height. // See how wide everyone is. Also remember max height.
for (__kindof UIView *subview in self.view.subviews) { for (__kindof UIView *subview in self.view.subviews) {
DoricLayout *childLayout = subview.doricLayout; DoricLayout *childLayout = subview.doricLayout;
@ -644,7 +702,8 @@ - (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricM
if (isExactly) { if (isExactly) {
totalLength += childLayout.marginLeft + childLayout.marginRight; totalLength += childLayout.marginLeft + childLayout.marginRight;
} else { } else {
totalLength = MAX(totalLength, totalLength + childLayout.marginLeft + childLayout.marginRight); totalLength = MAX(totalLength, totalLength
+childLayout.marginLeft + childLayout.marginRight);
} }
skippedMeasure = YES; skippedMeasure = YES;
} else { } else {
@ -695,6 +754,9 @@ - (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricM
CGFloat margin = childLayout.marginTop + childLayout.marginBottom; CGFloat margin = childLayout.marginTop + childLayout.marginBottom;
CGFloat childHeight = childLayout.measuredHeight + margin; CGFloat childHeight = childLayout.measuredHeight + margin;
childState = childState | childLayout.measuredState;
maxHeight = MAX(maxHeight, childHeight); maxHeight = MAX(maxHeight, childHeight);
allFillParent = allFillParent && childLayout.heightSpec == DoricLayoutMost; allFillParent = allFillParent && childLayout.heightSpec == DoricLayoutMost;
@ -706,7 +768,8 @@ - (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricM
*/ */
weightedMaxHeight = MAX(weightedMaxHeight, matchHeightLocally ? margin : childHeight); weightedMaxHeight = MAX(weightedMaxHeight, matchHeightLocally ? margin : childHeight);
} else { } else {
alternativeMaxHeight = MAX(alternativeMaxHeight, matchHeightLocally ? margin : childHeight); alternativeMaxHeight = MAX(alternativeMaxHeight,
matchHeightLocally ? margin : childHeight);
} }
} }
@ -722,7 +785,10 @@ - (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricM
widthSize = MAX(widthSize, self.minWidth); widthSize = MAX(widthSize, self.minWidth);
// Reconcile our calculated size with the widthMeasureSpec // Reconcile our calculated size with the widthMeasureSpec
widthSize = [self resolveSize:widthSize spec:widthMeasureSpec]; DoricSizeAndState widthSizeAndState = [self resolveSizeAndState:widthSize
spec:widthMeasureSpec
childMeasuredState:0];
widthSize = widthSizeAndState.size;
// Either expand children with weight to take up available space or // Either expand children with weight to take up available space or
// shrink them if they extend beyond our current bounds. If we skipped // shrink them if they extend beyond our current bounds. If we skipped
@ -743,11 +809,13 @@ - (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricM
weightSum -= childExtra; weightSum -= childExtra;
delta -= share; delta -= share;
DoricMeasureSpec childHeightMeasureSpec = [self getChildMeasureSpec:heightMeasureSpec DoricMeasureSpec childHeightMeasureSpec
padding:self.paddingTop + self.paddingBottom = [self getChildMeasureSpec:heightMeasureSpec
+ childLayout.marginTop + childLayout.marginBottom padding:self.paddingTop + self.paddingBottom
childLayoutSpec:childLayout.heightSpec + childLayout.marginTop
childSize:childLayout.height]; + childLayout.marginBottom
childLayoutSpec:childLayout.heightSpec
childSize:childLayout.height];
// TODO: Use a field like lp.isMeasured to figure out if this // TODO: Use a field like lp.isMeasured to figure out if this
// child has been previously measured // child has been previously measured
@ -763,19 +831,24 @@ - (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricM
height:childHeightMeasureSpec]; height:childHeightMeasureSpec];
} else { } else {
// child was skipped in the loop above. Measure for this first time here // child was skipped in the loop above. Measure for this first time here
[childLayout measureWidth:DoricMeasureSpecMake(DoricMeasureExactly, share > 0 ? share : 0) [childLayout measureWidth:DoricMeasureSpecMake(DoricMeasureExactly,
share > 0 ? share : 0)
height:childHeightMeasureSpec]; height:childHeightMeasureSpec];
} }
// Child may now not fit in horizontal dimension.
childState = childState | (childLayout.measuredState & DORIC_MEASURED_STATE_MASK);
} }
if (isExactly) { if (isExactly) {
totalLength += childLayout.measuredWidth + childLayout.marginLeft + childLayout.marginRight; totalLength += childLayout.measuredWidth
+ childLayout.marginLeft + childLayout.marginRight;
} else { } else {
totalLength = MAX(totalLength, totalLength + childLayout.measuredWidth totalLength = MAX(totalLength, totalLength + childLayout.measuredWidth
+ childLayout.marginLeft + childLayout.marginRight); + childLayout.marginLeft + childLayout.marginRight);
} }
totalLength += self.spacing; totalLength += self.spacing;
BOOL matchHeightLocally = heightMode != DoricMeasureExactly && childLayout.heightSpec == DoricLayoutMost; BOOL matchHeightLocally = heightMode != DoricMeasureExactly
&& childLayout.heightSpec == DoricLayoutMost;
CGFloat margin = childLayout.marginTop + childLayout.marginBottom; CGFloat margin = childLayout.marginTop + childLayout.marginBottom;
@ -783,7 +856,8 @@ - (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricM
maxHeight = MAX(maxHeight, childHeight); maxHeight = MAX(maxHeight, childHeight);
alternativeMaxHeight = MAX(alternativeMaxHeight, matchHeightLocally ? margin : childHeight); alternativeMaxHeight = MAX(alternativeMaxHeight,
matchHeightLocally ? margin : childHeight);
allFillParent = allFillParent && childLayout.heightSpec == DoricLayoutMost; allFillParent = allFillParent && childLayout.heightSpec == DoricLayoutMost;
} }
@ -809,7 +883,15 @@ - (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricM
maxHeight = MAX(maxHeight, self.minHeight); maxHeight = MAX(maxHeight, self.minHeight);
self.measuredWidth = widthSize; self.measuredWidth = widthSize;
self.measuredHeight = [self resolveSize:maxHeight spec:heightMeasureSpec]; DoricSizeAndState heightSizeAndState = [self resolveSizeAndState:maxHeight
spec:heightMeasureSpec
childMeasuredState:childState
<< DORIC_MEASURED_HEIGHT_STATE_SHIFT];
self.measuredHeight = heightSizeAndState.size;
self.measuredState = ((widthSizeAndState.state | (childState & DORIC_MEASURED_STATE_MASK))
<< DORIC_MEASURED_HEIGHT_STATE_SHIFT) | heightSizeAndState.state;
if (matchHeight) { if (matchHeight) {
[self forceUniformHeight:widthMeasureSpec]; [self forceUniformHeight:widthMeasureSpec];
@ -817,12 +899,14 @@ - (void)horizontalMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricM
self.totalLength = totalLength; self.totalLength = totalLength;
} }
- (void)stackMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMeasureSpec)heightMeasureSpec { - (void)stackMeasureWidth:(DoricMeasureSpec)widthMeasureSpec
height:(DoricMeasureSpec)heightMeasureSpec {
CGFloat maxWidth = 0; CGFloat maxWidth = 0;
CGFloat maxHeight = 0; CGFloat maxHeight = 0;
BOOL measureMatchParentChildren = widthMeasureSpec.mode != DoricMeasureExactly BOOL measureMatchParentChildren = widthMeasureSpec.mode != DoricMeasureExactly
|| heightMeasureSpec.mode != DoricMeasureExactly; || heightMeasureSpec.mode != DoricMeasureExactly;
NSMutableArray *matchParentChildren = [NSMutableArray new]; NSMutableArray *matchParentChildren = [NSMutableArray new];
NSUInteger childState = 0;
for (__kindof UIView *subview in self.view.subviews) { for (__kindof UIView *subview in self.view.subviews) {
DoricLayout *childLayout = subview.doricLayout; DoricLayout *childLayout = subview.doricLayout;
if (childLayout.disabled) { if (childLayout.disabled) {
@ -831,10 +915,14 @@ - (void)stackMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMeasur
[self measureChild:childLayout [self measureChild:childLayout
widthSpec:widthMeasureSpec usedWidth:0 widthSpec:widthMeasureSpec usedWidth:0
heightSpec:heightMeasureSpec usedHeight:0]; heightSpec:heightMeasureSpec usedHeight:0];
maxWidth = MAX(maxWidth, childLayout.measuredWidth + childLayout.marginLeft + childLayout.marginRight); maxWidth = MAX(maxWidth, childLayout.measuredWidth
maxHeight = MAX(maxHeight, childLayout.measuredHeight + childLayout.marginTop + childLayout.marginBottom); + childLayout.marginLeft + childLayout.marginRight);
maxHeight = MAX(maxHeight, childLayout.measuredHeight
+ childLayout.marginTop + childLayout.marginBottom);
childState = childState | childLayout.measuredState;
if (measureMatchParentChildren) { if (measureMatchParentChildren) {
if (childLayout.widthSpec == DoricLayoutMost || childLayout.heightSpec == DoricLayoutMost) { if (childLayout.widthSpec == DoricLayoutMost
|| childLayout.heightSpec == DoricLayoutMost) {
[matchParentChildren addObject:childLayout]; [matchParentChildren addObject:childLayout];
} }
} }
@ -848,46 +936,69 @@ - (void)stackMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMeasur
maxWidth = MAX(maxWidth, self.minWidth); maxWidth = MAX(maxWidth, self.minWidth);
maxHeight = MAX(maxHeight, self.minHeight); maxHeight = MAX(maxHeight, self.minHeight);
self.measuredWidth = [self resolveSize:maxWidth spec:widthMeasureSpec]; DoricSizeAndState widthSizeAndState = [self resolveSizeAndState:maxWidth
self.measuredHeight = [self resolveSize:maxHeight spec:heightMeasureSpec]; spec:widthMeasureSpec
childMeasuredState:childState];
DoricSizeAndState heightSizeAndState = [self resolveSizeAndState:maxHeight
spec:heightMeasureSpec
childMeasuredState:childState
<< DORIC_MEASURED_HEIGHT_STATE_SHIFT];
self.measuredWidth = widthSizeAndState.size;
self.measuredHeight = heightSizeAndState.size;
self.measuredState = (widthSizeAndState.state
<< DORIC_MEASURED_HEIGHT_STATE_SHIFT) | heightSizeAndState.state;
if (matchParentChildren.count > 1) { if (matchParentChildren.count > 1) {
for (DoricLayout *child in matchParentChildren) { for (DoricLayout *child in matchParentChildren) {
DoricMeasureSpec childWidthMeasureSpec; DoricMeasureSpec childWidthMeasureSpec;
if (child.widthSpec == DoricLayoutMost) { if (child.widthSpec == DoricLayoutMost) {
childWidthMeasureSpec.size = MAX(0, self.measuredWidth - self.paddingLeft - self.paddingRight childWidthMeasureSpec.size = MAX(0,
- child.marginLeft - child.marginRight); self.measuredWidth - self.paddingLeft - self.paddingRight
- child.marginLeft - child.marginRight);
childWidthMeasureSpec.mode = DoricMeasureExactly; childWidthMeasureSpec.mode = DoricMeasureExactly;
} else { } else {
childWidthMeasureSpec = [self getChildMeasureSpec:widthMeasureSpec childWidthMeasureSpec
padding:self.paddingLeft + self.paddingRight = [self getChildMeasureSpec:widthMeasureSpec
+ child.marginLeft + child.marginRight padding:self.paddingLeft + self.paddingRight
childLayoutSpec:child.widthSpec + child.marginLeft + child.marginRight
childSize:child.width]; childLayoutSpec:child.widthSpec
childSize:child.width];
} }
DoricMeasureSpec childHeightMeasureSpec; DoricMeasureSpec childHeightMeasureSpec;
if (child.heightSpec == DoricLayoutMost) { if (child.heightSpec == DoricLayoutMost) {
childHeightMeasureSpec.size = MAX(0, self.measuredHeight - self.paddingTop - self.paddingBottom childHeightMeasureSpec.size
= MAX(0, self.measuredHeight - self.paddingTop - self.paddingBottom
- child.marginTop - child.marginBottom); - child.marginTop - child.marginBottom);
childHeightMeasureSpec.mode = DoricMeasureExactly; childHeightMeasureSpec.mode = DoricMeasureExactly;
} else { } else {
childHeightMeasureSpec = [self getChildMeasureSpec:heightMeasureSpec childHeightMeasureSpec
padding:self.paddingTop + self.paddingBottom = [self getChildMeasureSpec:heightMeasureSpec
+ child.marginTop + child.marginBottom padding:self.paddingTop + self.paddingBottom
childLayoutSpec:child.heightSpec + child.marginTop + child.marginBottom
childSize:child.height]; childLayoutSpec:child.heightSpec
childSize:child.height];
} }
[child measureWidth:childWidthMeasureSpec height:childHeightMeasureSpec]; [child measureWidth:childWidthMeasureSpec height:childHeightMeasureSpec];
} }
} }
} }
- (void)undefinedMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMeasureSpec)heightMeasureSpec { - (void)undefinedMeasureWidth:(DoricMeasureSpec)widthMeasureSpec
height:(DoricMeasureSpec)heightMeasureSpec {
CGSize targetSize = CGSizeMake(widthMeasureSpec.size, heightMeasureSpec.size); CGSize targetSize = CGSizeMake(widthMeasureSpec.size, heightMeasureSpec.size);
//TODO should check this //TODO should check this
CGSize measuredSize = [self.view sizeThatFits:targetSize]; CGSize measuredSize = [self.view sizeThatFits:targetSize];
self.measuredWidth = [self resolveSize:measuredSize.width spec:widthMeasureSpec]; DoricSizeAndState widthSizeAndState = [self resolveSizeAndState:measuredSize.width
self.measuredHeight = [self resolveSize:measuredSize.height spec:heightMeasureSpec]; spec:widthMeasureSpec
childMeasuredState:0];
DoricSizeAndState heightSizeAndState = [self resolveSizeAndState:measuredSize.height
spec:heightMeasureSpec
childMeasuredState:0];
self.measuredWidth = widthSizeAndState.size;
self.measuredHeight = heightSizeAndState.size;
self.measuredState = (widthSizeAndState.state
<< DORIC_MEASURED_HEIGHT_STATE_SHIFT) | heightSizeAndState.state;
} }
#pragma layout #pragma layout
@ -920,12 +1031,17 @@ - (void)setFrame {
[obj.doricLayout setFrame]; [obj.doricLayout setFrame];
}]; }];
} }
CGRect originFrame = CGRectMake(self.measuredX, self.measuredY, self.measuredWidth, self.measuredHeight); CGRect originFrame = CGRectMake(self.measuredX, self.measuredY,
self.measuredWidth, self.measuredHeight);
if (!CGAffineTransformEqualToTransform(self.view.transform, CGAffineTransformIdentity)) { if (!CGAffineTransformEqualToTransform(self.view.transform, CGAffineTransformIdentity)) {
CGPoint anchor = self.view.layer.anchorPoint; CGPoint anchor = self.view.layer.anchorPoint;
originFrame = CGRectOffset(originFrame, -anchor.x * self.measuredWidth - self.measuredX, -anchor.y * self.measuredHeight - self.measuredY); originFrame = CGRectOffset(originFrame,
-anchor.x * self.measuredWidth - self.measuredX,
-anchor.y * self.measuredHeight - self.measuredY);
originFrame = CGRectApplyAffineTransform(originFrame, self.view.transform); originFrame = CGRectApplyAffineTransform(originFrame, self.view.transform);
originFrame = CGRectOffset(originFrame, anchor.x * self.measuredWidth + self.measuredX, anchor.y * self.measuredHeight + self.measuredY); originFrame = CGRectOffset(originFrame,
anchor.x * self.measuredWidth + self.measuredX,
anchor.y * self.measuredHeight + self.measuredY);
} }
BOOL isFrameChange = ![self rect:originFrame equalTo:self.view.frame]; BOOL isFrameChange = ![self rect:originFrame equalTo:self.view.frame];
if (isFrameChange) { if (isFrameChange) {
@ -975,7 +1091,8 @@ - (void)configMaskWithLayer:(CAShapeLayer *)shapeLayer {
lineLayer.path = path; lineLayer.path = path;
lineLayer.fillColor = nil; lineLayer.fillColor = nil;
[[self.view.layer sublayers] forEach:^(__kindof CALayer *obj) { [[self.view.layer sublayers] forEach:^(__kindof CALayer *obj) {
if ([obj isKindOfClass:CAShapeLayer.class] && ((CAShapeLayer *) obj).lineWidth > CGFLOAT_MIN) { if ([obj isKindOfClass:CAShapeLayer.class]
&& ((CAShapeLayer *) obj).lineWidth > CGFLOAT_MIN) {
[obj removeFromSuperlayer]; [obj removeFromSuperlayer];
} }
}]; }];
@ -1038,7 +1155,8 @@ - (void)layoutVLayout {
} else if ((self.gravity & DoricGravityBottom) == DoricGravityBottom) { } else if ((self.gravity & DoricGravityBottom) == DoricGravityBottom) {
yStart = self.measuredHeight - self.totalLength - self.paddingBottom; yStart = self.measuredHeight - self.totalLength - self.paddingBottom;
} else if ((self.gravity & DoricGravityCenterY) == DoricGravityCenterY) { } else if ((self.gravity & DoricGravityCenterY) == DoricGravityCenterY) {
yStart = (self.measuredHeight - self.totalLength - self.paddingTop - self.paddingBottom) / 2 + self.paddingTop; yStart = (self.measuredHeight - self.totalLength
- self.paddingTop - self.paddingBottom) / 2 + self.paddingTop;
} }
for (UIView *child in self.view.subviews) { for (UIView *child in self.view.subviews) {
DoricLayout *layout = child.doricLayout; DoricLayout *layout = child.doricLayout;
@ -1077,7 +1195,8 @@ - (void)layoutHLayout {
} else if ((self.gravity & DoricGravityRight) == DoricGravityRight) { } else if ((self.gravity & DoricGravityRight) == DoricGravityRight) {
xStart = self.measuredWidth - self.totalLength - self.paddingRight; xStart = self.measuredWidth - self.totalLength - self.paddingRight;
} else if ((self.gravity & DoricGravityCenterX) == DoricGravityCenterX) { } else if ((self.gravity & DoricGravityCenterX) == DoricGravityCenterX) {
xStart = (self.measuredWidth - self.totalLength - self.paddingLeft - self.paddingRight) / 2 + self.paddingLeft; xStart = (self.measuredWidth - self.totalLength
- self.paddingLeft - self.paddingRight) / 2 + self.paddingLeft;
} }
for (UIView *child in self.view.subviews) { for (UIView *child in self.view.subviews) {
DoricLayout *layout = child.doricLayout; DoricLayout *layout = child.doricLayout;