feat:refact DoricLayout and layout config

This commit is contained in:
pengfei.zhou 2019-11-15 15:38:24 +08:00
parent 3289513720
commit 6017e7120d
16 changed files with 355 additions and 405 deletions

View File

@ -85,10 +85,9 @@ public abstract class SuperNode<V extends View> extends ViewNode<V> {
protected abstract void blendSubNode(JSObject subProperties); protected abstract void blendSubNode(JSObject subProperties);
protected void blendSubLayoutConfig(ViewNode viewNode, JSObject jsObject) { protected void blendSubLayoutConfig(ViewNode viewNode, JSObject jsObject) {
JSValue jsValue = jsObject.getProperty("margin"); JSValue margin = jsObject.getProperty("margin");
JSValue widthSpec = jsObject.getProperty("widthSpec"); JSValue widthSpec = jsObject.getProperty("widthSpec");
JSValue heightSpec = jsObject.getProperty("heightSpec"); JSValue heightSpec = jsObject.getProperty("heightSpec");
ViewGroup.LayoutParams layoutParams = viewNode.getLayoutParams(); ViewGroup.LayoutParams layoutParams = viewNode.getLayoutParams();
if (widthSpec.isNumber()) { if (widthSpec.isNumber()) {
switch (widthSpec.asNumber().toInt()) { switch (widthSpec.asNumber().toInt()) {
@ -114,20 +113,20 @@ public abstract class SuperNode<V extends View> extends ViewNode<V> {
break; break;
} }
} }
if (jsValue.isObject() && layoutParams instanceof ViewGroup.MarginLayoutParams) { if (margin.isObject() && layoutParams instanceof ViewGroup.MarginLayoutParams) {
JSValue topVal = jsValue.asObject().getProperty("top"); JSValue topVal = margin.asObject().getProperty("top");
if (topVal.isNumber()) { if (topVal.isNumber()) {
((ViewGroup.MarginLayoutParams) layoutParams).topMargin = DoricUtils.dp2px(topVal.asNumber().toFloat()); ((ViewGroup.MarginLayoutParams) layoutParams).topMargin = DoricUtils.dp2px(topVal.asNumber().toFloat());
} }
JSValue leftVal = jsValue.asObject().getProperty("left"); JSValue leftVal = margin.asObject().getProperty("left");
if (leftVal.isNumber()) { if (leftVal.isNumber()) {
((ViewGroup.MarginLayoutParams) layoutParams).leftMargin = DoricUtils.dp2px(leftVal.asNumber().toFloat()); ((ViewGroup.MarginLayoutParams) layoutParams).leftMargin = DoricUtils.dp2px(leftVal.asNumber().toFloat());
} }
JSValue rightVal = jsValue.asObject().getProperty("right"); JSValue rightVal = margin.asObject().getProperty("right");
if (rightVal.isNumber()) { if (rightVal.isNumber()) {
((ViewGroup.MarginLayoutParams) layoutParams).rightMargin = DoricUtils.dp2px(rightVal.asNumber().toFloat()); ((ViewGroup.MarginLayoutParams) layoutParams).rightMargin = DoricUtils.dp2px(rightVal.asNumber().toFloat());
} }
JSValue bottomVal = jsValue.asObject().getProperty("bottom"); JSValue bottomVal = margin.asObject().getProperty("bottom");
if (bottomVal.isNumber()) { if (bottomVal.isNumber()) {
((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin = DoricUtils.dp2px(bottomVal.asNumber().toFloat()); ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin = DoricUtils.dp2px(bottomVal.asNumber().toFloat());
} }

View File

@ -30,7 +30,7 @@ - (void)viewDidLoad {
NSString *jsContent = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; NSString *jsContent = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
self.doricContext = [[DoricContext alloc] initWithScript:jsContent source:@"test.js"]; self.doricContext = [[DoricContext alloc] initWithScript:jsContent source:@"test.js"];
[self.doricContext.rootNode setupRootView:[[DoricStackView new] also:^(DoricStackView *it) { [self.doricContext.rootNode setupRootView:[[DoricStackView new] also:^(DoricStackView *it) {
it.layoutConfig = [[DoricStackConfig alloc] initWithWidth:DoricLayoutAtMost height:DoricLayoutAtMost]; it.layoutConfig = [[DoricLayoutConfig alloc] initWithWidth:DoricLayoutAtMost height:DoricLayoutAtMost];
[self.view addSubview:it]; [self.view addSubview:it];
}]]; }]];
[self.doricContext initContextWithWidth:self.view.width height:self.view.height]; [self.doricContext initContextWithWidth:self.view.width height:self.view.height];

View File

@ -24,7 +24,7 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface DoricGroupNode <V:UIView *, P:DoricLayoutConfig *> : DoricSuperNode<V, P> @interface DoricGroupNode <V:UIView *> : DoricSuperNode<V>
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -22,5 +22,5 @@
#import "DoricGroupNode.h" #import "DoricGroupNode.h"
@interface DoricHLayoutNode : DoricGroupNode<DoricHLayoutView *, DoricLinearConfig *> @interface DoricHLayoutNode : DoricGroupNode<DoricHLayoutView *>
@end @end

View File

@ -37,29 +37,4 @@ - (void)blendView:(DoricHLayoutView *)view forPropName:(NSString *)name propValu
[super blendView:view forPropName:name propValue:prop]; [super blendView:view forPropName:name propValue:prop];
} }
} }
- (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutConfig {
[super blendSubNode:subNode layoutConfig:layoutConfig];
if (![subNode.layoutConfig isKindOfClass:DoricLinearConfig.class]) {
DoricLog(@"blend DoricHLayoutView child error,layout params not match");
return;
}
DoricLinearConfig *params = (DoricLinearConfig *) subNode.layoutConfig;
NSDictionary *margin = layoutConfig[@"margin"];
if (margin) {
params.margin = DoricMarginMake(
[(NSNumber *) margin[@"left"] floatValue],
[(NSNumber *) margin[@"top"] floatValue],
[(NSNumber *) margin[@"right"] floatValue],
[(NSNumber *) margin[@"bottom"] floatValue]);
}
NSNumber *alignment = layoutConfig[@"alignment"];
if (alignment) {
params.alignment = (DoricGravity) [alignment integerValue];
}
}
- (DoricLinearConfig *)generateDefaultLayoutParams {
return [[DoricLinearConfig alloc] init];
}
@end @end

View File

@ -54,43 +54,27 @@ typedef NS_ENUM(NSInteger, DoricGravity) {
@interface DoricLayoutConfig : NSObject @interface DoricLayoutConfig : NSObject
@property(nonatomic, assign) DoricLayoutSpec widthSpec; @property(nonatomic, assign) DoricLayoutSpec widthSpec;
@property(nonatomic, assign) DoricLayoutSpec heightSpec; @property(nonatomic, assign) DoricLayoutSpec heightSpec;
@property(nonatomic) DoricMargin margin;
@property(nonatomic, assign) DoricGravity alignment; @property(nonatomic, assign) DoricGravity alignment;
@property(nonatomic, assign) NSUInteger weight;
- (instancetype)init; - (instancetype)init;
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height; - (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height;
@end
@interface DoricStackConfig : DoricLayoutConfig
@end
@interface DoricMarginConfig : DoricLayoutConfig
@property(nonatomic) DoricMargin margin;
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height margin:(DoricMargin)margin; - (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height margin:(DoricMargin)margin;
@end
@interface DoricLinearConfig : DoricMarginConfig
@property(nonatomic, assign) NSUInteger weight;
@end @end
@interface DoricLayoutContainer <T :DoricLayoutConfig *> : UIView @interface DoricLayoutContainer : UIView
- (T)configForChild:(__kindof UIView *)child;
- (void)layout;
- (void)requestLayout;
@end
@interface DoricStackView : DoricLayoutContainer<DoricStackConfig *>
@property(nonatomic, assign) DoricGravity gravity; @property(nonatomic, assign) DoricGravity gravity;
@end @end
@interface DoricLinearView : DoricLayoutContainer<DoricLinearConfig *> @interface DoricStackView : DoricLayoutContainer
@property(nonatomic, assign) DoricGravity gravity; @end
@interface DoricLinearView : DoricLayoutContainer
@property(nonatomic, assign) CGFloat space; @property(nonatomic, assign) CGFloat space;
@end @end

View File

@ -46,107 +46,74 @@ - (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)hei
} }
return self; return self;
} }
@end
@implementation DoricMarginConfig
- (instancetype)init {
if (self = [super init]) {
_margin = DoricMarginMake(0, 0, 0, 0);
}
return self;
}
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height margin:(DoricMargin)margin { - (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height margin:(DoricMargin)margin {
if (self = [super initWithWidth:width height:height]) { if (self = [super init]) {
_widthSpec = width;
_heightSpec = height;
_margin = margin; _margin = margin;
} }
return self; return self;
} }
@end @end
@implementation DoricStackConfig
@end
@implementation DoricLinearConfig
@end
@interface DoricLayoutContainer () @interface DoricLayoutContainer ()
@property(nonatomic, assign) BOOL waitingLayout; @property(nonatomic, assign) CGFloat contentWidth;
@property(nonatomic, assign) CGFloat contentHeight;
@property(nonatomic, assign) NSUInteger contentWeight;
- (void)layout:(CGSize)targetSize;
- (CGSize)sizeContent:(CGSize)size;
@end @end
@implementation DoricLayoutContainer @implementation DoricLayoutContainer
- (instancetype)init {
if (self = [super init]) {
_waitingLayout = NO;
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame { - (void)layoutSubviews {
if (self = [super initWithFrame:frame]) {
_waitingLayout = NO;
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
_waitingLayout = NO;
}
return self;
}
- (DoricLayoutConfig *)configForChild:(UIView *)child {
DoricLayoutConfig *config = child.layoutConfig;
if (!config) {
config = [[DoricLayoutConfig alloc] init];
}
return config;
}
- (void)requestLayout {
if ([self.superview isKindOfClass:[DoricLinearView class]]) {
[(DoricLinearView *) self.superview requestLayout];
return;
}
if (self.waitingLayout) {
return;
}
self.waitingLayout = YES;
__weak typeof(self) _self = self;
dispatch_async(dispatch_get_main_queue(), ^{
__strong typeof(_self) self = _self;
[self sizeToFit];
[self layout];
self.waitingLayout = NO;
});
}
- (void)setNeedsLayout {
[super setNeedsLayout];
if (self.waitingLayout) {
return;
}
[self requestLayout];
}
- (BOOL)waitingLayout {
if ([self.superview isKindOfClass:[DoricLayoutContainer class]]) { if ([self.superview isKindOfClass:[DoricLayoutContainer class]]) {
return [(DoricLayoutContainer *) self.superview waitingLayout]; [self.superview layoutSubviews];
} else {
CGSize size = [self sizeThatFits:CGSizeMake(self.superview.width, self.superview.height)];
[self layout:size];
} }
return _waitingLayout;
} }
- (void)layout { - (CGSize)sizeThatFits:(CGSize)size {
[self.subviews enumerateObjectsUsingBlock:^(__kindof UIView *child, NSUInteger idx, BOOL *stop) { CGFloat width = self.width;
if ([child isKindOfClass:[DoricLayoutContainer class]]) { CGFloat height = self.height;
[(DoricLayoutContainer *) child layout];
DoricLayoutConfig *config = self.layoutConfig;
if (!config) {
config = [DoricLayoutConfig new];
} }
}]; if (config.widthSpec == DoricLayoutAtMost
|| config.widthSpec == DoricLayoutWrapContent) {
width = size.width - config.margin.left - config.margin.right;
}
if (config.heightSpec == DoricLayoutAtMost
|| config.heightSpec == DoricLayoutWrapContent) {
height = size.height - config.margin.top - config.margin.bottom;
}
CGSize contentSize = [self sizeContent:CGSizeMake(width, height)];
if (config.widthSpec == DoricLayoutWrapContent) {
width = contentSize.width;
}
if (config.heightSpec == DoricLayoutWrapContent) {
height = contentSize.height;
}
return CGSizeMake(width, height);
} }
- (CGSize)sizeContent:(CGSize)size {
return size;
}
- (void)layout:(CGSize)targetSize {
self.width = targetSize.width;
self.height = targetSize.height;
}
@end @end
@ -157,175 +124,223 @@ @interface DoricStackView ()
@end @end
@implementation DoricStackView @implementation DoricStackView
- (DoricStackConfig *)configForChild:(UIView *)child {
DoricStackConfig *config = (DoricStackConfig *) child.layoutConfig;
if (!config) {
config = [[DoricStackConfig alloc] init];
}
return config;
}
- (CGSize)sizeContent:(CGSize)size {
- (void)sizeToFit { CGFloat contentWidth = 0;
DoricLayoutConfig *config = self.layoutConfig; CGFloat contentHeight = 0;
self.contentWidth = 0;
self.contentHeight = 0;
for (UIView *child in self.subviews) { for (UIView *child in self.subviews) {
if (child.isHidden) { if (child.isHidden) {
continue; continue;
} }
DoricStackConfig *childConfig = [self configForChild:child]; DoricLayoutConfig *childConfig = child.layoutConfig;
if (!childConfig) {
childConfig = [DoricLayoutConfig new];
}
CGSize childSize = CGSizeMake(child.width, child.height);
if ([child isKindOfClass:[DoricLayoutContainer class]] if ([child isKindOfClass:[DoricLayoutContainer class]]
|| childConfig.widthSpec == DoricLayoutWrapContent || childConfig.widthSpec == DoricLayoutWrapContent
|| childConfig.heightSpec == DoricLayoutWrapContent) { || childConfig.heightSpec == DoricLayoutWrapContent) {
[child sizeToFit]; childSize = [child sizeThatFits:CGSizeMake(size.width, size.height - contentHeight)];
} }
self.contentWidth = MAX(self.contentWidth, child.width); if (childConfig.widthSpec == DoricLayoutExact) {
self.contentHeight = MAX(self.contentHeight, child.height); childSize.width = child.width;
} else if (childConfig.widthSpec == DoricLayoutAtMost) {
childSize.width = size.width;
} }
if (config.widthSpec == DoricLayoutWrapContent) { if (childConfig.heightSpec == DoricLayoutExact) {
self.width = self.contentWidth; childSize.height = child.height;
} else if (config.widthSpec == DoricLayoutAtMost) { } else if (childConfig.heightSpec == DoricLayoutAtMost) {
self.width = self.superview.width; childSize.height = size.height - contentHeight;
} }
if (config.heightSpec == DoricLayoutWrapContent) {
self.height = self.contentHeight;
} else if (config.heightSpec == DoricLayoutAtMost) {
self.height = self.superview.height;
}
}
- (void)layout {
for (UIView *child in self.subviews) {
if (child.isHidden) {
continue;
}
DoricStackConfig *childConfig = [self configForChild:child];
DoricGravity gravity = childConfig.alignment | self.gravity;
if ((gravity & LEFT) == LEFT) {
child.left = 0;
} else if ((gravity & RIGHT) == RIGHT) {
child.right = self.width;
} else if ((gravity & CENTER_X) == CENTER_X) {
child.centerX = self.width / 2;
}
if ((gravity & TOP) == TOP) {
child.top = 0;
} else if ((gravity & BOTTOM) == BOTTOM) {
child.bottom = self.height;
} else if ((gravity & CENTER_Y) == CENTER_Y) {
child.centerY = self.height / 2;
}
if (childConfig.widthSpec == DoricLayoutAtMost) {
child.width = self.width;
}
if (childConfig.heightSpec == DoricLayoutAtMost) {
child.height = self.height;
}
if ([child isKindOfClass:[DoricLayoutContainer class]]) {
[(DoricLayoutContainer *) child layout];
}
}
}
@end
@interface DoricLinearView ()
@property(nonatomic, assign) CGFloat contentWidth;
@property(nonatomic, assign) CGFloat contentHeight;
@property(nonatomic, assign) NSUInteger contentWeight;
@end
@implementation DoricLinearView
- (DoricLinearConfig *)configForChild:(UIView *)child {
DoricLinearConfig *config = (DoricLinearConfig *) child.layoutConfig;
if (!config) {
config = [[DoricLinearConfig alloc] init];
}
return config;
}
@end
@implementation DoricVLayoutView
- (void)sizeToFit {
DoricLayoutConfig *config = self.layoutConfig;
self.contentWidth = 0;
self.contentHeight = 0;
self.contentWeight = 0;
for (UIView *child in self.subviews) {
if (child.isHidden) {
continue;
}
DoricLinearConfig *childConfig = [self configForChild:child];
if ([child isKindOfClass:[DoricLayoutContainer class]]
|| childConfig.widthSpec == DoricLayoutWrapContent
|| childConfig.heightSpec == DoricLayoutWrapContent) {
[child sizeToFit];
}
self.contentWidth = MAX(self.contentWidth, child.width + childConfig.margin.left + childConfig.margin.right);
self.contentHeight += child.height + self.space + childConfig.margin.top + childConfig.margin.bottom;
self.contentWeight += childConfig.weight;
}
self.contentHeight -= self.space;
if (config.widthSpec == DoricLayoutWrapContent) {
self.width = self.contentWidth;
} else if (config.widthSpec == DoricLayoutAtMost) {
self.width = self.superview.width;
}
if (config.heightSpec == DoricLayoutWrapContent) {
self.height = self.contentHeight;
} else if (config.heightSpec == DoricLayoutAtMost) {
self.height = self.superview.height;
}
if (self.contentWeight) {
CGFloat remain = self.height - self.contentHeight;
for (UIView *child in self.subviews) {
if (child.isHidden) {
continue;
}
DoricLinearConfig *childConfig = [self configForChild:child];
if (childConfig.weight) { if (childConfig.weight) {
child.height += remain / self.contentWeight * childConfig.weight; childSize.height = child.height;
} }
contentWidth = MAX(contentWidth, childSize.width + childConfig.margin.left + childConfig.margin.right);
contentHeight = MAX(contentHeight, childSize.height + childConfig.margin.top + childConfig.margin.bottom);
} }
self.contentHeight = self.height; self.contentWidth = contentWidth;
} self.contentHeight = contentHeight;
return CGSizeMake(contentWidth, contentHeight);
} }
- (void)layout { - (void)layout:(CGSize)targetSize {
CGFloat yStart = 0;
if ((self.gravity & TOP) == TOP) {
yStart = 0;
} else if ((self.gravity & BOTTOM) == BOTTOM) {
yStart = self.height - self.contentHeight;
} else if ((self.gravity & CENTER_Y) == CENTER_Y) {
yStart = (self.height - self.contentHeight) / 2;
}
for (UIView *child in self.subviews) { for (UIView *child in self.subviews) {
if (child.isHidden) { if (child.isHidden) {
continue; continue;
} }
DoricLinearConfig *childConfig = [self configForChild:child]; DoricLayoutConfig *childConfig = child.layoutConfig;
if (!childConfig) {
childConfig = [DoricLayoutConfig new];
}
CGSize size = [child sizeThatFits:CGSizeMake(targetSize.width, targetSize.height)];
if (childConfig.widthSpec == DoricLayoutExact) {
size.width = child.width;
}
if (childConfig.heightSpec == DoricLayoutExact) {
size.height = child.height;
}
if (childConfig.widthSpec == DoricLayoutExact) {
size.width = child.width;
} else if (childConfig.widthSpec == DoricLayoutAtMost) {
size.width = targetSize.width;
}
if (childConfig.heightSpec == DoricLayoutExact) {
size.height = child.height;
} else if (childConfig.heightSpec == DoricLayoutAtMost) {
size.height = targetSize.height;
}
child.width = size.width;
child.height = size.height;
DoricGravity gravity = childConfig.alignment | self.gravity; DoricGravity gravity = childConfig.alignment | self.gravity;
if ((gravity & LEFT) == LEFT) { if ((gravity & LEFT) == LEFT) {
child.left = 0; child.left = 0;
} else if ((gravity & RIGHT) == RIGHT) { } else if ((gravity & RIGHT) == RIGHT) {
child.right = self.width; child.right = targetSize.width;
} else if ((gravity & CENTER_X) == CENTER_X) { } else if ((gravity & CENTER_X) == CENTER_X) {
child.centerX = self.width / 2; child.centerX = targetSize.width / 2;
} else { } else {
if (childConfig.margin.left) { if (childConfig.margin.left) {
child.left = childConfig.margin.left; child.left = childConfig.margin.left;
} else if (childConfig.margin.right) { } else if (childConfig.margin.right) {
child.right = self.width - childConfig.margin.right; child.right = targetSize.width - childConfig.margin.right;
} }
} }
if (childConfig.widthSpec == DoricLayoutAtMost) {
child.width = self.width; if ((gravity & TOP) == TOP) {
child.top = 0;
} else if ((gravity & BOTTOM) == BOTTOM) {
child.bottom = targetSize.height;
} else if ((gravity & CENTER_Y) == CENTER_Y) {
child.centerY = targetSize.height / 2;
} else {
if (childConfig.margin.top) {
child.top = childConfig.margin.top;
} else if (childConfig.margin.bottom) {
child.bottom = targetSize.height - childConfig.margin.bottom;
}
}
if ([child isKindOfClass:[DoricLayoutContainer class]]) {
[(DoricLayoutContainer *) child layout:size];
}
}
self.width = targetSize.width;
self.height = targetSize.height;
}
@end
@implementation DoricLinearView
@end
@implementation DoricVLayoutView
- (CGSize)sizeContent:(CGSize)size {
CGFloat contentWidth = 0;
CGFloat contentHeight = 0;
NSUInteger contentWeight = 0;
for (UIView *child in self.subviews) {
if (child.isHidden) {
continue;
}
DoricLayoutConfig *childConfig = child.layoutConfig;
if (!childConfig) {
childConfig = [DoricLayoutConfig new];
}
CGSize childSize = CGSizeMake(child.width, child.height);
if ([child isKindOfClass:[DoricLayoutContainer class]]
|| childConfig.widthSpec == DoricLayoutWrapContent
|| childConfig.heightSpec == DoricLayoutWrapContent) {
childSize = [child sizeThatFits:CGSizeMake(size.width, size.height - contentHeight)];
}
if (childConfig.widthSpec == DoricLayoutExact) {
childSize.width = child.width;
} else if (childConfig.widthSpec == DoricLayoutAtMost) {
childSize.width = size.width;
}
if (childConfig.heightSpec == DoricLayoutExact) {
childSize.height = child.height;
} else if (childConfig.heightSpec == DoricLayoutAtMost) {
childSize.height = size.height - contentHeight;
}
if (childConfig.weight) {
childSize.height = child.height;
}
contentWidth = MAX(contentWidth, childSize.width + childConfig.margin.left + childConfig.margin.right);
contentHeight += childSize.height + self.space + childConfig.margin.top + childConfig.margin.bottom;
contentWeight += childConfig.weight;
}
contentHeight -= self.space;
self.contentWidth = contentWidth;
self.contentHeight = contentHeight;
self.contentWeight = contentWeight;
if (contentWeight) {
contentHeight = size.height;
}
return CGSizeMake(contentWidth, contentHeight);
}
- (void)layout:(CGSize)targetSize {
CGFloat yStart = 0;
if ((self.gravity & TOP) == TOP) {
yStart = 0;
} else if ((self.gravity & BOTTOM) == BOTTOM) {
yStart = targetSize.height - self.contentHeight;
} else if ((self.gravity & CENTER_Y) == CENTER_Y) {
yStart = (targetSize.height - self.contentHeight) / 2;
}
CGFloat remain = targetSize.height - self.contentHeight;
for (UIView *child in self.subviews) {
if (child.isHidden) {
continue;
}
DoricLayoutConfig *childConfig = child.layoutConfig;
if (!childConfig) {
childConfig = [DoricLayoutConfig new];
}
CGSize size = [child sizeThatFits:CGSizeMake(targetSize.width, targetSize.height - yStart)];
if (childConfig.widthSpec == DoricLayoutExact) {
size.width = child.width;
}
if (childConfig.heightSpec == DoricLayoutExact) {
size.height = child.height;
}
if (childConfig.widthSpec == DoricLayoutExact) {
size.width = child.width;
} else if (childConfig.widthSpec == DoricLayoutAtMost) {
size.width = targetSize.width;
}
if (childConfig.heightSpec == DoricLayoutExact) {
size.height = child.height;
} else if (childConfig.heightSpec == DoricLayoutAtMost) {
size.height = targetSize.height - yStart;
}
if (childConfig.weight) {
size.height = child.height;
}
if (childConfig.weight) {
size.height += remain / self.contentWeight * childConfig.weight;
}
child.width = size.width;
child.height = size.height;
DoricGravity gravity = childConfig.alignment | self.gravity;
if ((gravity & LEFT) == LEFT) {
child.left = 0;
} else if ((gravity & RIGHT) == RIGHT) {
child.right = self.width;
} else if ((gravity & CENTER_X) == CENTER_X) {
child.centerX = targetSize.width / 2;
} else {
if (childConfig.margin.left) {
child.left = childConfig.margin.left;
} else if (childConfig.margin.right) {
child.right = targetSize.width - childConfig.margin.right;
} }
if (childConfig.heightSpec == DoricLayoutAtMost) {
child.height = self.height - yStart - childConfig.margin.top - childConfig.margin.bottom - self.space;
} }
if (childConfig.margin.top) { if (childConfig.margin.top) {
yStart += childConfig.margin.top; yStart += childConfig.margin.top;
@ -336,102 +351,124 @@ - (void)layout {
yStart += childConfig.margin.bottom; yStart += childConfig.margin.bottom;
} }
if ([child isKindOfClass:[DoricLayoutContainer class]]) { if ([child isKindOfClass:[DoricLayoutContainer class]]) {
[(DoricLayoutContainer *) child layout]; [(DoricLayoutContainer *) child layout:size];
} }
} }
self.width = targetSize.width;
self.height = targetSize.height;
} }
@end @end
@implementation DoricHLayoutView @implementation DoricHLayoutView
- (void)sizeToFit {
DoricLinearConfig *config; - (CGSize)sizeContent:(CGSize)size {
if ([self.superview isKindOfClass:[DoricLinearView class]]) { CGFloat contentWidth = 0;
config = [(DoricLinearView *) self.superview configForChild:self]; CGFloat contentHeight = 0;
} else { NSUInteger contentWeight = 0;
config = (DoricLinearConfig *) self.layoutConfig;
if (!config) {
config = [[DoricLinearConfig alloc] init];
}
}
self.contentWidth = 0;
self.contentHeight = 0;
self.contentWeight = 0;
for (UIView *child in self.subviews) { for (UIView *child in self.subviews) {
if (child.isHidden) { if (child.isHidden) {
continue; continue;
} }
DoricLinearConfig *childConfig = [self configForChild:child]; DoricLayoutConfig *childConfig = child.layoutConfig;
if (!childConfig) {
childConfig = [DoricLayoutConfig new];
}
CGSize childSize = CGSizeMake(child.width, child.height);
if ([child isKindOfClass:[DoricLayoutContainer class]] if ([child isKindOfClass:[DoricLayoutContainer class]]
|| childConfig.widthSpec == DoricLayoutWrapContent || childConfig.widthSpec == DoricLayoutWrapContent
|| childConfig.heightSpec == DoricLayoutWrapContent) { || childConfig.heightSpec == DoricLayoutWrapContent) {
[child sizeToFit]; childSize = [child sizeThatFits:CGSizeMake(size.width - contentWidth, size.height)];
} }
self.contentHeight = MAX(self.contentHeight, child.height + childConfig.margin.top + childConfig.margin.bottom); if (childConfig.widthSpec == DoricLayoutExact) {
self.contentWidth += child.width + self.space + childConfig.margin.left + childConfig.margin.right; childSize.width = child.width;
self.contentWeight += childConfig.weight; } else if (childConfig.widthSpec == DoricLayoutAtMost) {
childSize.width = size.width - contentWidth;
} }
self.contentWidth -= self.space; if (childConfig.heightSpec == DoricLayoutExact) {
if (config.widthSpec == DoricLayoutWrapContent) { childSize.height = child.height;
self.width = self.contentWidth; } else if (childConfig.heightSpec == DoricLayoutAtMost) {
} else if (config.widthSpec == DoricLayoutAtMost) { childSize.height = size.height;
self.width = self.superview.width;
} }
if (config.heightSpec == DoricLayoutWrapContent) {
self.height = self.contentHeight;
} else if (config.heightSpec == DoricLayoutAtMost) {
self.height = self.superview.height;
}
if (self.contentWeight) {
CGFloat remain = self.width - self.contentWidth;
for (UIView *child in self.subviews) {
if (child.isHidden) {
continue;
}
DoricLinearConfig *childConfig = [self configForChild:child];
if (childConfig.weight) { if (childConfig.weight) {
child.width += remain / self.contentWeight * childConfig.weight; childSize.width = child.width;
} }
contentWidth += childSize.width + self.space + childConfig.margin.left + childConfig.margin.right;
contentHeight = MAX(contentHeight, childSize.height + childConfig.margin.top + childConfig.margin.bottom);
contentWeight += childConfig.weight;
} }
self.contentWidth = self.width; contentWidth -= self.space;
self.contentWidth = contentWidth;
self.contentHeight = contentHeight;
self.contentWeight = contentWeight;
if (contentWeight) {
contentWidth = size.width;
} }
return CGSizeMake(contentWidth, contentHeight);
} }
- (void)layout { - (void)layout:(CGSize)targetSize {
CGFloat xStart = 0; CGFloat xStart = 0;
if ((self.gravity & LEFT) == LEFT) { if (self.contentWeight) {
xStart = 0;
} else if ((self.gravity & LEFT) == LEFT) {
xStart = 0; xStart = 0;
} else if ((self.gravity & RIGHT) == RIGHT) { } else if ((self.gravity & RIGHT) == RIGHT) {
xStart = self.width - self.contentWidth; xStart = targetSize.width - self.contentWidth;
} else if ((self.gravity & CENTER_X) == CENTER_X) { } else if ((self.gravity & CENTER_X) == CENTER_X) {
xStart = (self.width - self.contentWidth) / 2; xStart = (targetSize.width - self.contentWidth) / 2;
} }
CGFloat remain = targetSize.width - self.contentWidth;
for (UIView *child in self.subviews) { for (UIView *child in self.subviews) {
if (child.isHidden) { if (child.isHidden) {
continue; continue;
} }
DoricLinearConfig *childConfig = [self configForChild:child]; DoricLayoutConfig *childConfig = child.layoutConfig;
if (!childConfig) {
childConfig = [DoricLayoutConfig new];
}
CGSize size = [child sizeThatFits:CGSizeMake(targetSize.width - xStart, targetSize.height)];
if (childConfig.widthSpec == DoricLayoutExact) {
size.width = child.width;
}
if (childConfig.heightSpec == DoricLayoutExact) {
size.height = child.height;
}
if (childConfig.widthSpec == DoricLayoutExact) {
size.width = child.width;
} else if (childConfig.widthSpec == DoricLayoutAtMost) {
size.width = targetSize.width - xStart;
}
if (childConfig.heightSpec == DoricLayoutExact) {
size.height = child.height;
} else if (childConfig.heightSpec == DoricLayoutAtMost) {
size.height = targetSize.height;
}
if (childConfig.weight) {
size.width = child.width;
}
if (childConfig.weight) {
size.width += remain / self.contentWeight * childConfig.weight;
}
child.width = size.width;
child.height = size.height;
DoricGravity gravity = childConfig.alignment | self.gravity; DoricGravity gravity = childConfig.alignment | self.gravity;
if ((gravity & TOP) == TOP) { if ((gravity & TOP) == TOP) {
child.top = 0; child.top = 0;
} else if ((gravity & BOTTOM) == BOTTOM) { } else if ((gravity & BOTTOM) == BOTTOM) {
child.bottom = self.height; child.bottom = targetSize.height;
} else if ((gravity & CENTER_Y) == CENTER_Y) { } else if ((gravity & CENTER_Y) == CENTER_Y) {
child.centerY = self.height / 2; child.centerY = targetSize.height / 2;
} else { } else {
if (childConfig.margin.top) { if (childConfig.margin.top) {
child.top = childConfig.margin.top; child.top = childConfig.margin.top;
} else if (childConfig.margin.bottom) { } else if (childConfig.margin.bottom) {
child.bottom = self.height - childConfig.margin.bottom; child.bottom = targetSize.height - childConfig.margin.bottom;
} }
} }
if (childConfig.heightSpec == DoricLayoutAtMost) {
child.height = self.height;
}
if (childConfig.widthSpec == DoricLayoutAtMost) {
child.width = self.width - xStart - childConfig.margin.right - childConfig.margin.left - self.space;
}
if (childConfig.margin.left) { if (childConfig.margin.left) {
xStart += childConfig.margin.left; xStart += childConfig.margin.left;
} }
@ -441,9 +478,11 @@ - (void)layout {
xStart += childConfig.margin.right; xStart += childConfig.margin.right;
} }
if ([child isKindOfClass:[DoricLayoutContainer class]]) { if ([child isKindOfClass:[DoricLayoutContainer class]]) {
[(DoricLayoutContainer *) child layout]; [(DoricLayoutContainer *) child layout:size];
} }
} }
self.width = targetSize.width;
self.height = targetSize.height;
} }
@end @end

View File

@ -31,6 +31,6 @@ - (void)render:(NSDictionary *)props {
[self blend:props]; [self blend:props];
} }
- (void)requestLayout { - (void)requestLayout {
[self.view requestLayout]; [self.view setNeedsLayout];
} }
@end @end

View File

@ -22,5 +22,5 @@
#import "DoricGroupNode.h" #import "DoricGroupNode.h"
@interface DoricStackNode : DoricGroupNode<DoricStackView *, DoricStackConfig *> @interface DoricStackNode : DoricGroupNode<DoricStackView *>
@end @end

View File

@ -21,7 +21,6 @@
// //
#import "DoricStackNode.h" #import "DoricStackNode.h"
#import "DoricUtil.h"
@implementation DoricStackNode @implementation DoricStackNode
@ -36,22 +35,4 @@ - (void)blendView:(DoricStackView *)view forPropName:(NSString *)name propValue:
[super blendView:view forPropName:name propValue:prop]; [super blendView:view forPropName:name propValue:prop];
} }
} }
- (DoricStackConfig *)generateDefaultLayoutParams {
return [[DoricStackConfig alloc] init];
}
- (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutConfig {
[super blendSubNode:subNode layoutConfig:layoutConfig];
if (![subNode.layoutConfig isKindOfClass:DoricStackConfig.class]) {
DoricLog(@"blend DoricHLayoutView child error,layout params not match");
return;
}
DoricStackConfig *params = (DoricStackConfig *) subNode.layoutConfig;
NSNumber *alignment = layoutConfig[@"alignment"];
if (alignment) {
params.alignment = (DoricGravity) [alignment integerValue];
}
}
@end @end

View File

@ -20,8 +20,8 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "DoricViewNode.h" #import "DoricViewNode.h"
@interface DoricSuperNode<V:UIView *, P:DoricLayoutConfig *> : DoricViewNode<V> @interface DoricSuperNode<V:UIView *> : DoricViewNode<V>
- (P)generateDefaultLayoutParams; - (DoricLayoutConfig *)generateDefaultLayoutParams;
- (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutConfig; - (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutConfig;

View File

@ -80,17 +80,20 @@ - (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layou
} }
}]; }];
if ([params isKindOfClass:DoricMarginConfig.class]) {
DoricMarginConfig *marginParams = (DoricMarginConfig *) params;
NSDictionary *margin = layoutConfig[@"margin"]; NSDictionary *margin = layoutConfig[@"margin"];
if (margin) { if (margin) {
marginParams.margin = DoricMarginMake( params.margin = DoricMarginMake(
[(NSNumber *) margin[@"left"] floatValue], [(NSNumber *) margin[@"left"] floatValue],
[(NSNumber *) margin[@"top"] floatValue], [(NSNumber *) margin[@"top"] floatValue],
[(NSNumber *) margin[@"right"] floatValue], [(NSNumber *) margin[@"right"] floatValue],
[(NSNumber *) margin[@"bottom"] floatValue]); [(NSNumber *) margin[@"bottom"] floatValue]);
} }
NSNumber *alignment = layoutConfig[@"alignment"];
if (alignment) {
params.alignment = (DoricGravity) [alignment integerValue];
} }
} }
- (void)blendSubNode:(NSDictionary *)subModel { - (void)blendSubNode:(NSDictionary *)subModel {

View File

@ -22,5 +22,5 @@
#import "DoricGroupNode.h" #import "DoricGroupNode.h"
@interface DoricVLayoutNode : DoricGroupNode<DoricVLayoutView *, DoricLinearConfig *> @interface DoricVLayoutNode : DoricGroupNode<DoricVLayoutView *>
@end @end

View File

@ -21,7 +21,6 @@
// //
#import "DoricVLayoutNode.h" #import "DoricVLayoutNode.h"
#import "DoricUtil.h"
@implementation DoricVLayoutNode @implementation DoricVLayoutNode
@ -39,28 +38,4 @@ - (void)blendView:(DoricVLayoutView *)view forPropName:(NSString *)name propValu
} }
} }
- (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutconfig {
[super blendSubNode:subNode layoutConfig:layoutconfig];
if (![subNode.layoutConfig isKindOfClass:DoricLinearConfig.class]) {
DoricLog(@"blend DoricVLayoutView child error,layout params not match");
return;
}
DoricLinearConfig *params = (DoricLinearConfig *) subNode.layoutConfig;
NSDictionary *margin = layoutconfig[@"margin"];
if (margin) {
params.margin = DoricMarginMake(
[(NSNumber *) margin[@"left"] floatValue],
[(NSNumber *) margin[@"top"] floatValue],
[(NSNumber *) margin[@"right"] floatValue],
[(NSNumber *) margin[@"bottom"] floatValue]);
}
NSNumber *alignment = layoutconfig[@"alignment"];
if (alignment) {
params.alignment = (DoricGravity) [alignment integerValue];
}
}
- (DoricLinearConfig *)generateDefaultLayoutParams {
return [[DoricLinearConfig alloc] init];
}
@end @end

View File

@ -16,14 +16,6 @@
import { LayoutConfig, Group, Property, IView } from "./view"; import { LayoutConfig, Group, Property, IView } from "./view";
import { Gravity } from "../util/gravity"; import { Gravity } from "../util/gravity";
export interface StackConfig extends LayoutConfig {
}
export interface LinearConfig extends LayoutConfig {
weight?: number
}
export interface IStack extends IView { export interface IStack extends IView {
gravity?: Gravity gravity?: Gravity
} }

View File

@ -35,6 +35,8 @@ export interface LayoutConfig {
bottom?: number, bottom?: number,
} }
alignment?: Gravity alignment?: Gravity
//Only affective in VLayout or HLayout
weight?: number
} }
export function Property(target: Object, propKey: string) { export function Property(target: Object, propKey: string) {