diff --git a/doric-iOS/Pod/Classes/Shader/DoricFlexNode.m b/doric-iOS/Pod/Classes/Shader/DoricFlexNode.m index ec07a71a..e0c28930 100644 --- a/doric-iOS/Pod/Classes/Shader/DoricFlexNode.m +++ b/doric-iOS/Pod/Classes/Shader/DoricFlexNode.m @@ -20,56 +20,19 @@ #import #import "DoricFlexNode.h" #import "DoricExtensions.h" -#import "UIView+Yoga.h" +#import @interface DoricFlexView : UIView @end @implementation DoricFlexView -- (CGSize)sizeThatFits:(CGSize)size { - for (UIView *view in self.subviews) { - [view.doricLayout measure:size]; - [view configureLayoutWithBlock:^(YGLayout *layout) { - layout.isEnabled = YES; - if (view.doricLayout.undefined) { - return; - } - if (layout.width.unit == YGUnitUndefined - || layout.width.unit == YGUnitAuto) { - layout.width = YGPointValue(view.doricLayout.measuredWidth); - } - if (layout.height.unit == YGUnitUndefined - || layout.height.unit == YGUnitAuto) { - layout.height = YGPointValue(view.doricLayout.measuredHeight); - } - }]; - } - if (self.yoga.isLeaf) { - return CGSizeZero; - } - YGValue maxWidth = self.yoga.maxWidth; - YGValue maxHeight = self.yoga.maxHeight; - if (maxWidth.unit == YGUnitPoint) { - self.yoga.maxWidth = YGPointValue(MIN(maxWidth.value, size.width)); - } else { - self.yoga.maxWidth = YGPointValue(size.width); - } - if (maxHeight.unit == YGUnitPoint) { - self.yoga.maxHeight = YGPointValue(MIN(maxHeight.value, size.height)); - } else { - self.yoga.maxHeight = YGPointValue(size.height); - } - CGSize ret = [self.yoga intrinsicSize]; - self.yoga.maxWidth = maxWidth; - self.yoga.maxHeight = maxHeight; - return ret; -} @end @implementation DoricFlexNode - (UIView *)build { return [[DoricFlexView new] also:^(DoricFlexView *it) { it.clipsToBounds = YES; + it.doricLayout.layoutType = DoricFlexLayout; [it configureLayoutWithBlock:^(YGLayout *_Nonnull layout) { layout.isEnabled = YES; }]; @@ -78,6 +41,7 @@ - (UIView *)build { - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop { if ([name isEqualToString:@"flexConfig"]) { + view.doricLayout.flexConfig = prop; [self blendYoga:view.yoga from:prop]; } else { [super blendView:view forPropName:name propValue:prop]; @@ -94,6 +58,7 @@ - (void)afterBlended:(NSDictionary *)props { viewNode.view.yoga.width = YGValueAuto; viewNode.view.yoga.height = YGValueAuto; } + viewNode.view.yoga.isEnabled = YES; }]; } @@ -101,7 +66,6 @@ - (void)blendSubNode:(DoricViewNode *)subNode flexConfig:(NSDictionary *)flexCon [subNode.view configureLayoutWithBlock:^(YGLayout *_Nonnull layout) { layout.isEnabled = YES; }]; - subNode.view.doricLayout.disabled = YES; subNode.view.yoga.width = YGValueAuto; subNode.view.yoga.height = YGValueAuto; [self blendYoga:subNode.view.yoga from:flexConfig]; @@ -243,53 +207,4 @@ - (YGValue)translateYGValueFromProperty:(id)prop { return YGValueAuto; } } - -- (void)requestLayout { - if (self.view.doricLayout.widthSpec != DoricLayoutFit) { - self.view.yoga.width = YGPointValue(self.view.width); - } - if (self.view.doricLayout.heightSpec != DoricLayoutFit) { - self.view.yoga.height = YGPointValue(self.view.height); - } - if (![self.superNode isKindOfClass:DoricFlexNode.class]) { - self.view.yoga.margin = YGValueZero; - self.view.yoga.marginLeft = YGValueZero; - self.view.yoga.marginRight = YGValueZero; - self.view.yoga.marginTop = YGValueZero; - self.view.yoga.marginBottom = YGValueZero; - self.view.yoga.marginStart = YGValueZero; - self.view.yoga.marginEnd = YGValueZero; - self.view.yoga.marginVertical = YGValueZero; - self.view.yoga.marginHorizontal = YGValueZero; - CGSize size = self.view.yoga.intrinsicSize; - if (self.view.yoga.maxWidth.unit != YGUnitPoint - || (self.view.yoga.maxWidth.unit == YGUnitPoint && self.view.yoga.maxWidth.value > size.width)) { - self.view.yoga.maxWidth = YGValueUndefined; - } - if (self.view.yoga.maxHeight.unit != YGUnitPoint - || (self.view.yoga.maxHeight.unit == YGUnitPoint && self.view.yoga.maxHeight.value > size.height)) { - self.view.yoga.maxHeight = YGValueUndefined; - } - } - [self.view.yoga applyLayoutPreservingOrigin:YES]; - /// Need layout again. - for (UIView *view in self.view.subviews) { - if ([view isKindOfClass:[DoricFlexView class]]) { - continue; - } - if (view.doricLayout.undefined) { - continue; - } - if (view.doricLayout.measuredWidth != view.width || view.doricLayout.measuredHeight != view.height) { - view.doricLayout.widthSpec = DoricLayoutJust; - view.doricLayout.heightSpec = DoricLayoutJust; - view.doricLayout.width = view.width; - view.doricLayout.height = view.height; - } - view.doricLayout.measuredX = view.left; - view.doricLayout.measuredY = view.top; - [view.doricLayout apply]; - } - [super requestLayout]; -} @end diff --git a/doric-iOS/Pod/Classes/Shader/DoricLayouts.h b/doric-iOS/Pod/Classes/Shader/DoricLayouts.h index a376f4b5..436f9f62 100644 --- a/doric-iOS/Pod/Classes/Shader/DoricLayouts.h +++ b/doric-iOS/Pod/Classes/Shader/DoricLayouts.h @@ -45,6 +45,7 @@ typedef NS_ENUM(NSInteger, DoricLayoutType) { DoricVLayout = 2, DoricHLayout = 3, DoricScroller = 4, + DoricFlexLayout = 5, }; typedef NS_ENUM(NSInteger, DoricLayoutSpec) { @@ -120,6 +121,8 @@ typedef NS_ENUM(NSInteger, DoricGravity) { @property(nonatomic, assign) CGFloat totalLength; +@property(nonatomic, assign) NSDictionary *flexConfig; + - (instancetype)init; - (void)measure:(CGSize)targetSize; diff --git a/doric-iOS/Pod/Classes/Shader/DoricLayouts.m b/doric-iOS/Pod/Classes/Shader/DoricLayouts.m index c5b4f34e..93e65c2e 100644 --- a/doric-iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/doric-iOS/Pod/Classes/Shader/DoricLayouts.m @@ -21,6 +21,8 @@ #import #import "UIView+Doric.h" #import "DoricExtensions.h" +#import +#import #import void DoricAddEllipticArcPath(CGMutablePathRef path, @@ -472,6 +474,10 @@ - (void)measureWidth:(DoricMeasureSpec)widthSpec height:(DoricMeasureSpec)height [self scrollerMeasureWidth:widthSpec height:heightSpec]; break; } + case DoricFlexLayout: { + [self flexMeasureWidth:widthSpec height:heightSpec]; + break; + } default: { [self undefinedMeasureWidth:widthSpec height:heightSpec]; break; @@ -1089,6 +1095,134 @@ - (void)scrollerMeasureWidth:(DoricMeasureSpec)widthMeasureSpec [childLayout measureWidth:childWidthMeasureSpec height:childHeightMeasureSpec]; } +- (void)flexMeasureWidth:(DoricMeasureSpec)widthMeasureSpec + height:(DoricMeasureSpec)heightMeasureSpec { + + for (__kindof UIView *subview in self.view.subviews) { + DoricLayout *childDoricLayout = subview.doricLayout; + YGLayout *childYGLayout = subview.yoga; + DoricMeasureSpec childWidthMeasureSpec; + DoricMeasureSpec childHeightMeasureSpec; + if (childDoricLayout.widthSpec == DoricLayoutMost) { + childWidthMeasureSpec = DoricMeasureSpecMake(DoricMeasureAtMost, self.measuredWidth); + } else if (childDoricLayout.widthSpec == DoricLayoutFit) { + childWidthMeasureSpec = DoricMeasureSpecMake(DoricMeasureUnspecified, 0); + } else { + childWidthMeasureSpec = DoricMeasureSpecMake(DoricMeasureExactly, childDoricLayout.width); + } + + if (childDoricLayout.heightSpec == DoricLayoutMost) { + childHeightMeasureSpec = DoricMeasureSpecMake(DoricMeasureAtMost, self.measuredHeight); + } else if (childDoricLayout.heightSpec == DoricLayoutFit) { + childHeightMeasureSpec = DoricMeasureSpecMake(DoricMeasureUnspecified, 0); + } else { + childHeightMeasureSpec = DoricMeasureSpecMake(DoricMeasureExactly, childDoricLayout.height); + } + [childDoricLayout measureWidth:childWidthMeasureSpec height:childHeightMeasureSpec]; + if (childDoricLayout.layoutType != DoricFlexLayout) { + YGUnit widthUnit = YGUnitAuto; + YGUnit heightUnit = YGUnitAuto; + if (childDoricLayout.flexConfig) { + id widthValue = childDoricLayout.flexConfig[@"width"]; + if ([widthValue isKindOfClass:NSNumber.class]) { + widthUnit = YGUnitPoint; + } else if ([widthValue isKindOfClass:NSDictionary.class]) { + id type = widthValue[@"type"]; + if ([type isKindOfClass:NSNumber.class]) { + widthUnit = (YGUnit) [type integerValue]; + } + } + + id heightValue = childDoricLayout.flexConfig[@"height"]; + if ([heightValue isKindOfClass:NSNumber.class]) { + heightUnit = YGUnitPoint; + } else if ([heightValue isKindOfClass:NSDictionary.class]) { + id type = heightValue[@"type"]; + if ([type isKindOfClass:NSNumber.class]) { + heightUnit = (YGUnit) [type integerValue]; + } + } + } + if (widthUnit == YGUnitAuto) { + childYGLayout.width = YGPointValue(childDoricLayout.measuredWidth); + } + + if (heightUnit == YGUnitAuto) { + childYGLayout.height = YGPointValue(childDoricLayout.measuredHeight); + } + } + } + + + YGUnit widthUnit = YGUnitAuto; + YGUnit heightUnit = YGUnitAuto; + if (self.flexConfig) { + id widthValue = self.flexConfig[@"width"]; + if ([widthValue isKindOfClass:NSNumber.class]) { + widthUnit = YGUnitPoint; + } else if ([widthValue isKindOfClass:NSDictionary.class]) { + id type = widthValue[@"type"]; + if ([type isKindOfClass:NSNumber.class]) { + widthUnit = (YGUnit) [type integerValue]; + } + } + + id heightValue = self.flexConfig[@"height"]; + if ([heightValue isKindOfClass:NSNumber.class]) { + heightUnit = YGUnitPoint; + } else if ([heightValue isKindOfClass:NSDictionary.class]) { + id type = heightValue[@"type"]; + if ([type isKindOfClass:NSNumber.class]) { + heightUnit = (YGUnit) [type integerValue]; + } + } + } + if (widthUnit == YGUnitAuto) { + self.view.yoga.width = YGValueAuto; + } + + if (heightUnit == YGUnitAuto) { + self.view.yoga.height = YGValueAuto; + } + + if (self.view.superview.doricLayout.layoutType != DoricFlexLayout) { + if (heightMeasureSpec.mode == DoricMeasureAtMost) { + heightMeasureSpec = DoricMeasureSpecMake(DoricMeasureUnspecified, heightMeasureSpec.size); + } + + if (widthMeasureSpec.mode == DoricMeasureAtMost) { + widthMeasureSpec = DoricMeasureSpecMake(DoricMeasureUnspecified, widthMeasureSpec.size); + } + + if (heightMeasureSpec.mode == DoricMeasureExactly) { + self.view.yoga.height = YGPointValue(heightMeasureSpec.size); + } + if (widthMeasureSpec.mode == DoricMeasureExactly) { + self.view.yoga.width = YGPointValue(widthMeasureSpec.size); + } + + if (heightMeasureSpec.mode == DoricMeasureAtMost) { + self.view.yoga.maxHeight = YGPointValue(heightMeasureSpec.size); + } + + if (widthMeasureSpec.mode == DoricMeasureAtMost) { + self.view.yoga.maxWidth = YGPointValue(widthMeasureSpec.size); + } + + [self.view.yoga intrinsicSize]; + } + + + DoricSizeAndState widthSizeAndState = [self resolveSizeAndState:YGNodeLayoutGetWidth(self.view.yoga.node) + spec:widthMeasureSpec + childMeasuredState:0]; + self.measuredWidth = widthSizeAndState.size; + DoricSizeAndState heightSizeAndState = [self resolveSizeAndState:YGNodeLayoutGetHeight(self.view.yoga.node) + spec:heightMeasureSpec + childMeasuredState:0]; + self.measuredHeight = heightSizeAndState.size; +} + - (void)undefinedMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMeasureSpec)heightMeasureSpec { CGSize targetSize = CGSizeMake(widthMeasureSpec.size - self.paddingLeft - self.paddingRight, @@ -1162,6 +1296,10 @@ - (void)layout { [self layoutScroller]; break; } + case DoricFlexLayout: { + [self layoutFlex]; + break; + } default: { break; } @@ -1385,6 +1523,24 @@ - (void)layoutScroller { } [layout layout]; } + +- (void)layoutFlex { + for (UIView *child in self.view.subviews) { + DoricLayout *layout = child.doricLayout; + if (layout.disabled) { + continue; + } + if (layout.layoutType == DoricFlexLayout) { + [layout measureWidth:DoricMeasureSpecMake(DoricMeasureExactly, + YGNodeLayoutGetWidth(child.yoga.node)) + height:DoricMeasureSpecMake(DoricMeasureExactly, + YGNodeLayoutGetHeight(child.yoga.node))]; + } + [layout layout]; + layout.measuredX = YGNodeLayoutGetLeft(child.yoga.node); + layout.measuredY = YGNodeLayoutGetTop(child.yoga.node); + } +} @end @@ -1402,4 +1558,4 @@ - (void)layoutSubviews { [super layoutSubviews]; self.contentSize = self.contentView.frame.size; } -@end \ No newline at end of file +@end diff --git a/doric-iOS/Pod/Classes/Shader/DoricViewNode.m b/doric-iOS/Pod/Classes/Shader/DoricViewNode.m index 2b6fcc95..4b206193 100644 --- a/doric-iOS/Pod/Classes/Shader/DoricViewNode.m +++ b/doric-iOS/Pod/Classes/Shader/DoricViewNode.m @@ -262,6 +262,7 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop if ([self.superNode isKindOfClass:[DoricFlexNode class]]) { [((DoricFlexNode *) self.superNode) blendSubNode:self flexConfig:prop]; } + self.view.doricLayout.flexConfig = prop; } } else { DoricLog(@"Blend View error for View Type :%@, prop is %@", self.class, name);