iOS: Add DoricFlexLayout to DoricLayouts
This commit is contained in:
parent
390ef52632
commit
8e22108cc9
@ -20,56 +20,19 @@
|
|||||||
#import <YogaKit/UIView+Yoga.h>
|
#import <YogaKit/UIView+Yoga.h>
|
||||||
#import "DoricFlexNode.h"
|
#import "DoricFlexNode.h"
|
||||||
#import "DoricExtensions.h"
|
#import "DoricExtensions.h"
|
||||||
#import "UIView+Yoga.h"
|
#import <YogaKit/UIView+Yoga.h>
|
||||||
|
|
||||||
@interface DoricFlexView : UIView
|
@interface DoricFlexView : UIView
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation DoricFlexView
|
@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
|
@end
|
||||||
|
|
||||||
@implementation DoricFlexNode
|
@implementation DoricFlexNode
|
||||||
- (UIView *)build {
|
- (UIView *)build {
|
||||||
return [[DoricFlexView new] also:^(DoricFlexView *it) {
|
return [[DoricFlexView new] also:^(DoricFlexView *it) {
|
||||||
it.clipsToBounds = YES;
|
it.clipsToBounds = YES;
|
||||||
|
it.doricLayout.layoutType = DoricFlexLayout;
|
||||||
[it configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
|
[it configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
|
||||||
layout.isEnabled = YES;
|
layout.isEnabled = YES;
|
||||||
}];
|
}];
|
||||||
@ -78,6 +41,7 @@ - (UIView *)build {
|
|||||||
|
|
||||||
- (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
|
- (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||||
if ([name isEqualToString:@"flexConfig"]) {
|
if ([name isEqualToString:@"flexConfig"]) {
|
||||||
|
view.doricLayout.flexConfig = prop;
|
||||||
[self blendYoga:view.yoga from:prop];
|
[self blendYoga:view.yoga from:prop];
|
||||||
} else {
|
} else {
|
||||||
[super blendView:view forPropName:name propValue:prop];
|
[super blendView:view forPropName:name propValue:prop];
|
||||||
@ -94,6 +58,7 @@ - (void)afterBlended:(NSDictionary *)props {
|
|||||||
viewNode.view.yoga.width = YGValueAuto;
|
viewNode.view.yoga.width = YGValueAuto;
|
||||||
viewNode.view.yoga.height = 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) {
|
[subNode.view configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
|
||||||
layout.isEnabled = YES;
|
layout.isEnabled = YES;
|
||||||
}];
|
}];
|
||||||
subNode.view.doricLayout.disabled = YES;
|
|
||||||
subNode.view.yoga.width = YGValueAuto;
|
subNode.view.yoga.width = YGValueAuto;
|
||||||
subNode.view.yoga.height = YGValueAuto;
|
subNode.view.yoga.height = YGValueAuto;
|
||||||
[self blendYoga:subNode.view.yoga from:flexConfig];
|
[self blendYoga:subNode.view.yoga from:flexConfig];
|
||||||
@ -243,53 +207,4 @@ - (YGValue)translateYGValueFromProperty:(id)prop {
|
|||||||
return YGValueAuto;
|
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
|
@end
|
||||||
|
@ -45,6 +45,7 @@ typedef NS_ENUM(NSInteger, DoricLayoutType) {
|
|||||||
DoricVLayout = 2,
|
DoricVLayout = 2,
|
||||||
DoricHLayout = 3,
|
DoricHLayout = 3,
|
||||||
DoricScroller = 4,
|
DoricScroller = 4,
|
||||||
|
DoricFlexLayout = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, DoricLayoutSpec) {
|
typedef NS_ENUM(NSInteger, DoricLayoutSpec) {
|
||||||
@ -120,6 +121,8 @@ typedef NS_ENUM(NSInteger, DoricGravity) {
|
|||||||
|
|
||||||
@property(nonatomic, assign) CGFloat totalLength;
|
@property(nonatomic, assign) CGFloat totalLength;
|
||||||
|
|
||||||
|
@property(nonatomic, assign) NSDictionary *flexConfig;
|
||||||
|
|
||||||
- (instancetype)init;
|
- (instancetype)init;
|
||||||
|
|
||||||
- (void)measure:(CGSize)targetSize;
|
- (void)measure:(CGSize)targetSize;
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
#import "UIView+Doric.h"
|
#import "UIView+Doric.h"
|
||||||
#import "DoricExtensions.h"
|
#import "DoricExtensions.h"
|
||||||
|
#import <YogaKit/UIView+Yoga.h>
|
||||||
|
#import <YogaKit/YGLayout+Private.h>
|
||||||
#import <QuartzCore/QuartzCore.h>
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
void DoricAddEllipticArcPath(CGMutablePathRef path,
|
void DoricAddEllipticArcPath(CGMutablePathRef path,
|
||||||
@ -472,6 +474,10 @@ - (void)measureWidth:(DoricMeasureSpec)widthSpec height:(DoricMeasureSpec)height
|
|||||||
[self scrollerMeasureWidth:widthSpec height:heightSpec];
|
[self scrollerMeasureWidth:widthSpec height:heightSpec];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DoricFlexLayout: {
|
||||||
|
[self flexMeasureWidth:widthSpec height:heightSpec];
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
[self undefinedMeasureWidth:widthSpec height:heightSpec];
|
[self undefinedMeasureWidth:widthSpec height:heightSpec];
|
||||||
break;
|
break;
|
||||||
@ -1089,6 +1095,134 @@ - (void)scrollerMeasureWidth:(DoricMeasureSpec)widthMeasureSpec
|
|||||||
[childLayout measureWidth:childWidthMeasureSpec height:childHeightMeasureSpec];
|
[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
|
- (void)undefinedMeasureWidth:(DoricMeasureSpec)widthMeasureSpec
|
||||||
height:(DoricMeasureSpec)heightMeasureSpec {
|
height:(DoricMeasureSpec)heightMeasureSpec {
|
||||||
CGSize targetSize = CGSizeMake(widthMeasureSpec.size - self.paddingLeft - self.paddingRight,
|
CGSize targetSize = CGSizeMake(widthMeasureSpec.size - self.paddingLeft - self.paddingRight,
|
||||||
@ -1162,6 +1296,10 @@ - (void)layout {
|
|||||||
[self layoutScroller];
|
[self layoutScroller];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DoricFlexLayout: {
|
||||||
|
[self layoutFlex];
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1385,6 +1523,24 @@ - (void)layoutScroller {
|
|||||||
}
|
}
|
||||||
[layout layout];
|
[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
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@ -262,6 +262,7 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
|
|||||||
if ([self.superNode isKindOfClass:[DoricFlexNode class]]) {
|
if ([self.superNode isKindOfClass:[DoricFlexNode class]]) {
|
||||||
[((DoricFlexNode *) self.superNode) blendSubNode:self flexConfig:prop];
|
[((DoricFlexNode *) self.superNode) blendSubNode:self flexConfig:prop];
|
||||||
}
|
}
|
||||||
|
self.view.doricLayout.flexConfig = prop;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DoricLog(@"Blend View error for View Type :%@, prop is %@", self.class, name);
|
DoricLog(@"Blend View error for View Type :%@, prop is %@", self.class, name);
|
||||||
|
Reference in New Issue
Block a user