iOS refact DoricLayout

This commit is contained in:
pengfei.zhou 2020-04-03 16:36:43 +08:00 committed by osborn
parent ca6a3284f2
commit abbe0ba377
32 changed files with 540 additions and 761 deletions

View File

@ -81,7 +81,7 @@ - (void)setLeft:(NSDictionary *)params withPromise:(DoricPromise *)promise {
viewNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) { viewNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
it.viewId = viewId; it.viewId = viewId;
[it initWithSuperNode:nil]; [it initWithSuperNode:nil];
it.view.layoutConfig = [DoricLayoutConfig new]; it.view.doricLayout = [DoricLayout new];
[self.doricContext.navBar doric_navBar_setLeft:it.view]; [self.doricContext.navBar doric_navBar_setLeft:it.view];
NSMutableDictionary <NSString *, DoricViewNode *> *map = self.doricContext.headNodes[TYPE_LEFT]; NSMutableDictionary <NSString *, DoricViewNode *> *map = self.doricContext.headNodes[TYPE_LEFT];
@ -112,7 +112,7 @@ - (void)setRight:(NSDictionary *)params withPromise:(DoricPromise *)promise {
viewNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) { viewNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
it.viewId = viewId; it.viewId = viewId;
[it initWithSuperNode:nil]; [it initWithSuperNode:nil];
it.view.layoutConfig = [DoricLayoutConfig new]; it.view.doricLayout = [DoricLayout new];
[self.doricContext.navBar doric_navBar_setRight:it.view]; [self.doricContext.navBar doric_navBar_setRight:it.view];
NSMutableDictionary <NSString *, DoricViewNode *> *map = self.doricContext.headNodes[TYPE_RIGHT]; NSMutableDictionary <NSString *, DoricViewNode *> *map = self.doricContext.headNodes[TYPE_RIGHT];

View File

@ -17,7 +17,8 @@ - (void)show:(NSDictionary *)params withPromise:(DoricPromise *)promise {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
UIView *superView = [UIApplication sharedApplication].windows.lastObject; UIView *superView = [UIApplication sharedApplication].windows.lastObject;
if (!self.fullScreenView) { if (!self.fullScreenView) {
self.fullScreenView = [[DoricStackView new] also:^(UIView *it) { self.fullScreenView = [[UIView new] also:^(UIView *it) {
it.doricLayout.layoutType = DoricStack;
it.width = superView.width; it.width = superView.width;
it.height = superView.height; it.height = superView.height;
it.top = it.left = 0; it.top = it.left = 0;
@ -33,7 +34,7 @@ - (void)show:(NSDictionary *)params withPromise:(DoricPromise *)promise {
viewNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) { viewNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
it.viewId = viewId; it.viewId = viewId;
[it initWithSuperNode:nil]; [it initWithSuperNode:nil];
it.view.layoutConfig = [DoricLayoutConfig new]; it.view.doricLayout = [DoricLayout new];
[self.fullScreenView addSubview:it.view]; [self.fullScreenView addSubview:it.view];
NSMutableDictionary <NSString *, DoricViewNode *> *map = self.doricContext.headNodes[TYPE]; NSMutableDictionary <NSString *, DoricViewNode *> *map = self.doricContext.headNodes[TYPE];

View File

@ -54,40 +54,40 @@ - (instancetype)init {
return self; return self;
} }
- (CGSize)sizeThatFits:(CGSize)size { //- (CGSize)sizeThatFits:(CGSize)size {
if (self.contentView) { // if (self.contentView) {
return [self.contentView measureSize:size]; // return [self.contentView measureSize:size];
} // }
return CGSizeZero; // return CGSizeZero;
} //}
//
- (BOOL)requestFromSubview:(UIView *)subview { //- (BOOL)requestFromSubview:(UIView *)subview {
if (subview == self.headerView) { // if (subview == self.headerView) {
return NO; // return NO;
} // }
return [super requestFromSubview:subview]; // return [super requestFromSubview:subview];
} //}
- (void)layoutSubviews { - (void)layoutSubviews {
[super layoutSubviews]; [super layoutSubviews];
} }
- (void)layoutSelf:(CGSize)targetSize { //- (void)layoutSelf:(CGSize)targetSize {
if (self.contentOffset.y != 0) { // if (self.contentOffset.y != 0) {
return; // return;
} // }
self.width = targetSize.width; // self.width = targetSize.width;
self.height = targetSize.height; // self.height = targetSize.height;
[self.headerView also:^(UIView *it) { // [self.headerView also:^(UIView *it) {
[it layoutSelf:[it measureSize:targetSize]]; // [it layoutSelf:[it measureSize:targetSize]];
it.bottom = 0; // it.bottom = 0;
it.centerX = self.centerX; // it.centerX = self.centerX;
}]; // }];
[self.contentView also:^(UIView *it) { // [self.contentView also:^(UIView *it) {
[it layoutSelf:targetSize]; // [it layoutSelf:targetSize];
}]; // }];
self.contentSize = self.frame.size; // self.contentSize = self.frame.size;
} //}
- (void)setContentView:(UIView *)contentView { - (void)setContentView:(UIView *)contentView {
if (_contentView) { if (_contentView) {

View File

@ -23,8 +23,8 @@
#import "DoricDraggableNode.h" #import "DoricDraggableNode.h"
@implementation DoricDraggableNode @implementation DoricDraggableNode
- (DoricStackView *)build { - (UIView *)build {
DoricStackView *stackView = [DoricStackView new]; UIView *stackView = [UIView new];
UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onDrag:)]; UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onDrag:)];
[stackView addGestureRecognizer:gesture]; [stackView addGestureRecognizer:gesture];
return stackView; return stackView;
@ -40,7 +40,7 @@ - (void)onDrag:(UIPanGestureRecognizer *)gesture {
[self callJSResponse:_onDragFunction, @(originalFrame.origin.x), @(originalFrame.origin.y), nil]; [self callJSResponse:_onDragFunction, @(originalFrame.origin.x), @(originalFrame.origin.y), nil];
} }
- (void)blendView:(DoricStackView *)view forPropName:(NSString *)name propValue:(id)prop { - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([name isEqualToString:@"onDrag"]) { if ([name isEqualToString:@"onDrag"]) {
_onDragFunction = prop; _onDragFunction = prop;
} else { } else {

View File

@ -19,7 +19,7 @@
#import "DoricFlowLayoutItemNode.h" #import "DoricFlowLayoutItemNode.h"
@interface DoricFlowLayoutItemView : DoricStackView @interface DoricFlowLayoutItemView : UIView
@end @end
@implementation DoricFlowLayoutItemView @implementation DoricFlowLayoutItemView
@ -42,7 +42,7 @@ - (void)initWithSuperNode:(DoricSuperNode *)superNode {
self.reusable = YES; self.reusable = YES;
} }
- (DoricStackView *)build { - (DoricFlowLayoutItemView *)build {
return [DoricFlowLayoutItemView new]; return [DoricFlowLayoutItemView new];
} }
@end @end

View File

@ -139,23 +139,6 @@ @interface DoricFlowLayoutView : UICollectionView
@end @end
@implementation DoricFlowLayoutView @implementation DoricFlowLayoutView
- (CGSize)sizeThatFits:(CGSize)size {
if (self.subviews.count > 0) {
CGFloat width = size.width;
CGFloat height = size.height;
for (UIView *child in self.subviews) {
CGSize childSize = [child measureSize:size];
width = MAX(childSize.width, width);
height = MAX(childSize.height, height);
}
return CGSizeMake(width, height);
}
return size;
}
- (void)layoutSelf:(CGSize)targetSize {
[super layoutSelf:targetSize];
}
@end @end
@interface DoricFlowLayoutNode () <UICollectionViewDataSource, UICollectionViewDelegate, DoricFlowLayoutDelegate> @interface DoricFlowLayoutNode () <UICollectionViewDataSource, UICollectionViewDelegate, DoricFlowLayoutDelegate>
@ -336,14 +319,14 @@ - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collection
node.viewId = model[@"id"]; node.viewId = model[@"id"];
[node blend:props]; [node blend:props];
CGFloat width = (collectionView.width - (self.columnCount - 1) * self.columnSpace) / self.columnCount; CGFloat width = (collectionView.width - (self.columnCount - 1) * self.columnSpace) / self.columnCount;
CGSize size = [node.view measureSize:CGSizeMake(width, collectionView.height)]; // CGSize size = [node.view measureSize:CGSizeMake(width, collectionView.height)];
if (position > 0 && position >= self.itemCount && self.onLoadMoreFuncId) { // if (position > 0 && position >= self.itemCount && self.onLoadMoreFuncId) {
size = CGSizeMake(collectionView.width, size.height); // size = CGSizeMake(collectionView.width, size.height);
[self callJSResponse:self.onLoadMoreFuncId, nil]; // [self callJSResponse:self.onLoadMoreFuncId, nil];
} // }
//
[node.view layoutSelf:size]; // [node.view layoutSelf:size];
[self callItem:position size:size]; // [self callItem:position size:size];
return cell; return cell;
} }

View File

@ -51,16 +51,10 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
} }
} }
- (void)blend:(NSDictionary *)props { - (void)afterBlended:(NSDictionary *)props {
[super blend:props];
[self configChildNodes]; [self configChildNodes];
} }
- (DoricLayoutConfig *)generateDefaultLayoutParams {
DoricLayoutConfig *params = [[DoricLayoutConfig alloc] init];
return params;
}
- (void)configChildNodes { - (void)configChildNodes {
NSMutableArray *childNodes = [self.childNodes mutableCopy]; NSMutableArray *childNodes = [self.childNodes mutableCopy];
for (NSUInteger idx = 0; idx < self.childViewIds.count; idx++) { for (NSUInteger idx = 0; idx < self.childViewIds.count; idx++) {

View File

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

View File

@ -21,18 +21,20 @@
// //
#import "DoricHLayoutNode.h" #import "DoricHLayoutNode.h"
#import "DoricUtil.h" #import "DoricExtensions.h"
@implementation DoricHLayoutNode @implementation DoricHLayoutNode
- (DoricHLayoutView *)build { - (UIView *)build {
return [DoricHLayoutView new]; return [[UIView new] also:^(UIView *it) {
it.doricLayout.layoutType = DoricHLayout;
}];
} }
- (void)blendView:(DoricHLayoutView *)view forPropName:(NSString *)name propValue:(id)prop { - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([name isEqualToString:@"gravity"]) { if ([name isEqualToString:@"gravity"]) {
view.gravity = (DoricGravity) [(NSNumber *) prop integerValue]; view.doricLayout.gravity = (DoricGravity) [(NSNumber *) prop integerValue];
} else if ([name isEqualToString:@"space"]) { } else if ([name isEqualToString:@"space"]) {
view.space = [(NSNumber *) prop floatValue]; view.doricLayout.spacing = [(NSNumber *) prop floatValue];
} else { } else {
[super blendView:view forPropName:name propValue:prop]; [super blendView:view forPropName:name propValue:prop];
} }

View File

@ -28,46 +28,9 @@ @interface DoricImageView : YYAnimatedImageView
@end @end
@implementation DoricImageView @implementation DoricImageView
- (CGSize)measureSize:(CGSize)targetSize {
CGFloat width = self.width;
CGFloat height = self.height;
DoricLayoutConfig *config = self.layoutConfig; - (CGSize)sizeThatFits:(CGSize)size {
if (!config) { return [self sizeThatFits:size];
config = [DoricLayoutConfig new];
}
if (config.widthSpec == DoricLayoutMost
|| config.widthSpec == DoricLayoutFit) {
width = targetSize.width - config.margin.left - config.margin.right;
}
if (config.heightSpec == DoricLayoutMost
|| config.heightSpec == DoricLayoutFit) {
height = targetSize.height - config.margin.top - config.margin.bottom;
}
DoricPadding padding = self.padding;
CGSize contentSize = [self sizeThatFits:CGSizeMake(
width - padding.left - padding.right,
height - padding.top - padding.bottom)];
if (config.widthSpec == DoricLayoutFit) {
width = contentSize.width + padding.left + padding.right;
if (config.heightSpec != DoricLayoutFit && contentSize.width != 0 && contentSize.height != 0) {
width = contentSize.width / contentSize.height * height + padding.left + padding.right;
}
}
if (config.heightSpec == DoricLayoutFit) {
height = contentSize.height + padding.top + padding.bottom;
if (config.widthSpec != DoricLayoutFit && contentSize.width != 0 && contentSize.height != 0) {
height = contentSize.height / contentSize.width * width + padding.top + padding.bottom;
}
}
if (config.weight) {
if ([self.superview isKindOfClass:[DoricVLayoutView class]]) {
height = self.height;
} else if ([self.superview isKindOfClass:[DoricHLayoutView class]]) {
width = self.width;
}
}
return CGSizeMake(width, height);
} }
@end @end

View File

@ -26,6 +26,14 @@ typedef UIEdgeInsets DoricPadding;
DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom); DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom);
typedef NS_ENUM(NSInteger, DoricLayoutType) {
DoricUndefined = 0,
DoricStack = 1,
DoricVLayout = 2,
DoricHLayout = 3,
};
typedef NS_ENUM(NSInteger, DoricLayoutSpec) { typedef NS_ENUM(NSInteger, DoricLayoutSpec) {
DoricLayoutJust = 0, DoricLayoutJust = 0,
DoricLayoutFit = 1, DoricLayoutFit = 1,
@ -40,67 +48,52 @@ typedef NS_ENUM(NSInteger, DoricGravity) {
DoricGravityShiftY = 4, DoricGravityShiftY = 4,
DoricGravityLeft = (DoricGravityStart | DoricGravitySpecified) << DoricGravityShiftX, DoricGravityLeft = (DoricGravityStart | DoricGravitySpecified) << DoricGravityShiftX,
DoricGravityRight = (DoricGravityEnd | DoricGravitySpecified) << DoricGravityShiftX, DoricGravityRight = (DoricGravityEnd | DoricGravitySpecified) << DoricGravityShiftX,
DoricGravityTOP = (DoricGravityStart | DoricGravitySpecified) << DoricGravityShiftY, DoricGravityTop = (DoricGravityStart | DoricGravitySpecified) << DoricGravityShiftY,
DoricGravityBottom = (DoricGravityEnd | DoricGravitySpecified) << DoricGravityShiftY, DoricGravityBottom = (DoricGravityEnd | DoricGravitySpecified) << DoricGravityShiftY,
DoricGravityCenterX = DoricGravitySpecified << DoricGravityShiftX, DoricGravityCenterX = DoricGravitySpecified << DoricGravityShiftX,
DoricGravityCenterY = DoricGravitySpecified << DoricGravityShiftY, DoricGravityCenterY = DoricGravitySpecified << DoricGravityShiftY,
DoricGravityCenter = DoricGravityCenterX | DoricGravityCenterY, DoricGravityCenter = DoricGravityCenterX | DoricGravityCenterY,
}; };
@interface DoricLayoutConfig : NSObject @interface DoricLayout : 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) DoricGravity gravity;
@property(nonatomic, assign) CGFloat width;
@property(nonatomic, assign) CGFloat height;
@property(nonatomic, assign) CGFloat x;
@property(nonatomic, assign) CGFloat y;
@property(nonatomic, assign) CGFloat spacing;
@property(nonatomic, assign) CGFloat marginLeft;
@property(nonatomic, assign) CGFloat marginTop;
@property(nonatomic, assign) CGFloat marginRight;
@property(nonatomic, assign) CGFloat marginBottom;
@property(nonatomic, assign) CGFloat paddingLeft;
@property(nonatomic, assign) CGFloat paddingTop;
@property(nonatomic, assign) CGFloat paddingRight;
@property(nonatomic, assign) CGFloat paddingBottom;
@property(nonatomic, assign) NSUInteger weight; @property(nonatomic, assign) NSUInteger weight;
@property(nonatomic, weak) UIView *view;
@property(nonatomic, assign) DoricLayoutType layoutType;
@property(nonatomic, assign) BOOL disabled;
- (instancetype)init; - (instancetype)init;
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height; - (void)apply;
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height margin:(DoricMargin)margin;
@end @end
@interface DoricLayoutContainer : UIView @interface UIView (DoricLayout)
@end @property(nonatomic, strong) DoricLayout *doricLayout;
@interface DoricStackView : DoricLayoutContainer
@end
@interface DoricLinearView : DoricLayoutContainer
@property(nonatomic, assign) DoricGravity gravity;
@property(nonatomic, assign) CGFloat space;
@end
@interface DoricVLayoutView : DoricLinearView
@end
@interface DoricHLayoutView : DoricLinearView
@end
@interface UIView (DoricLayoutConfig)
@property(nonatomic, strong) DoricLayoutConfig *layoutConfig;
@end
@interface UIView (DoricPadding)
@property(nonatomic, assign) DoricPadding padding;
@end
@interface UIView (DoricTag)
@property(nonatomic, copy) NSString *tagString;
- (UIView *)viewWithTagString:(NSString *)tagString;
@end
@interface UIView (DoricLayouts)
- (void)layoutSelf:(CGSize)targetSize;
- (CGSize)measureSize:(CGSize)targetSize;
- (void)doricLayoutSubviews;
- (BOOL)requestFromSubview:(UIView *)subview;
@end @end

View File

@ -20,138 +20,45 @@
#import "DoricLayouts.h" #import "DoricLayouts.h"
#import <objc/runtime.h> #import <objc/runtime.h>
#import "UIView+Doric.h" #import "UIView+Doric.h"
#import "DoricExtensions.h"
static const void *kLayoutConfig = &kLayoutConfig; static const void *kLayoutConfig = &kLayoutConfig;
@implementation UIView (DoricLayoutConfig) @implementation UIView (DoricLayout)
@dynamic layoutConfig; @dynamic doricLayout;
- (void)setLayoutConfig:(DoricLayoutConfig *)layoutConfig { - (void)setDoricLayout:(DoricLayout *)doricLayout {
objc_setAssociatedObject(self, kLayoutConfig, layoutConfig, OBJC_ASSOCIATION_RETAIN_NONATOMIC); objc_setAssociatedObject(self, kLayoutConfig, doricLayout, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} }
- (DoricLayoutConfig *)layoutConfig { - (DoricLayout *)doricLayout {
return objc_getAssociatedObject(self, kLayoutConfig); DoricLayout *layout = objc_getAssociatedObject(self, kLayoutConfig);
if (!layout) {
layout = [DoricLayout new];
layout.width = self.width;
layout.height = self.height;
layout.x = self.x;
layout.y = self.y;
layout.view = self;
self.doricLayout = layout;
}
return layout;
} }
@end @end
static const void *kLayoutPadding = &kLayoutPadding; @interface DoricLayout ()
@property(nonatomic, assign) CGFloat contentWidth;
@implementation UIView (DoricPadding) @property(nonatomic, assign) CGFloat contentHeight;
@dynamic padding; @property(nonatomic, assign) CGFloat measuredWidth;
- (void)setPadding:(DoricPadding)padding {
objc_setAssociatedObject(self, kLayoutPadding, [NSValue value:&padding withObjCType:@encode(DoricPadding)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (DoricPadding)padding {
DoricPadding value;
value.left = value.right = value.top = value.bottom = 0;
[objc_getAssociatedObject(self, kLayoutPadding) getValue:&value];
return value;
}
@property(nonatomic, assign) CGFloat measuredHeight;
@property(nonatomic, assign) CGFloat measuredX;
@property(nonatomic, assign) CGFloat measuredY;
@property(nonatomic, assign) BOOL resolved;
@end @end
static const void *kTagString = &kTagString; @implementation DoricLayout
@implementation UIView (DoricTag)
- (void)setTagString:(NSString *)tagString {
objc_setAssociatedObject(self, kTagString, tagString, OBJC_ASSOCIATION_COPY_NONATOMIC);
self.tag = [tagString hash];
}
- (NSString *)tagString {
return objc_getAssociatedObject(self, kTagString);
}
- (UIView *)viewWithTagString:(NSString *)tagString {
// notice the potential hash collision
return [self viewWithTag:[tagString hash]];
}
@end
@implementation UIView (DoricLayouts)
/**
* Measure self's size
* */
- (CGSize)measureSize:(CGSize)targetSize {
CGFloat width = self.width;
CGFloat height = self.height;
DoricLayoutConfig *config = self.layoutConfig;
if (!config) {
config = [DoricLayoutConfig new];
}
if (config.widthSpec == DoricLayoutMost
|| config.widthSpec == DoricLayoutFit) {
width = targetSize.width - config.margin.left - config.margin.right;
}
if (config.heightSpec == DoricLayoutMost
|| config.heightSpec == DoricLayoutFit) {
height = targetSize.height - config.margin.top - config.margin.bottom;
}
DoricPadding padding = self.padding;
CGSize contentSize = [self sizeThatFits:CGSizeMake(
width - padding.left - padding.right,
height - padding.top - padding.bottom)];
if (config.widthSpec == DoricLayoutFit) {
width = contentSize.width + padding.left + padding.right;
}
if (config.heightSpec == DoricLayoutFit) {
height = contentSize.height + padding.top + padding.bottom;
}
if (config.weight) {
if ([self.superview isKindOfClass:[DoricVLayoutView class]]) {
height = self.height;
} else if ([self.superview isKindOfClass:[DoricHLayoutView class]]) {
width = self.width;
}
}
return CGSizeMake(width, height);
}
/**
* layout self and subviews
* */
- (void)layoutSelf:(CGSize)targetSize {
self.width = targetSize.width;
self.height = targetSize.height;
for (UIView *view in self.subviews) {
[view layoutSelf:[view measureSize:targetSize]];
}
}
- (void)doricLayoutSubviews {
if ([self.superview requestFromSubview:self]) {
[self.superview doricLayoutSubviews];
} else {
CGSize size = [self measureSize:CGSizeMake(self.superview.width, self.superview.height)];
[self layoutSelf:size];
}
}
- (BOOL)requestFromSubview:(UIView *)subview {
if (self.layoutConfig
&& self.layoutConfig.widthSpec != DoricLayoutJust
&& self.layoutConfig.heightSpec != DoricLayoutJust) {
return YES;
}
return NO;
}
@end
DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom) {
return UIEdgeInsetsMake(top, left, bottom, right);
}
@implementation DoricLayoutConfig
- (instancetype)init { - (instancetype)init {
if (self = [super init]) { if (self = [super init]) {
_widthSpec = DoricLayoutJust; _widthSpec = DoricLayoutJust;
@ -160,349 +67,317 @@ - (instancetype)init {
return self; return self;
} }
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height { - (void)apply {
if (self = [super init]) { if (!CGAffineTransformEqualToTransform(self.view.transform, CGAffineTransformIdentity)) {
_widthSpec = width; return;
_heightSpec = height;
} }
return self; self.resolved = NO;
[self measure:self.view.frame.size];
[self layout];
[self setFrame];
} }
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height margin:(DoricMargin)margin { - (void)measure:(CGSize)targetSize {
if (self = [super init]) { if (self.widthSpec == DoricLayoutMost) {
_widthSpec = width; self.measuredWidth = targetSize.width;
_heightSpec = height; } else {
_margin = margin; self.measuredWidth = self.width;
} }
return self; if (self.heightSpec == DoricLayoutMost) {
} self.measuredHeight = targetSize.height;
@end } else{
self.measuredHeight = self.height;
}
@interface DoricLayoutContainer () [self measureContent:CGSizeMake(
@property(nonatomic, assign) CGFloat contentWidth; self.measuredWidth - self.paddingLeft - self.paddingRight,
@property(nonatomic, assign) CGFloat contentHeight; self.measuredHeight - self.paddingTop - self.paddingBottom)];
@property(nonatomic, assign) NSUInteger contentWeight; self.resolved = YES;
@end
@implementation DoricLayoutContainer
- (void)setNeedsLayout {
[super setNeedsLayout];
} }
- (void)layoutSubviews { - (void)measureContent:(CGSize)targetSize {
[super layoutSubviews]; switch (self.layoutType) {
[self doricLayoutSubviews]; case DoricStack: {
[self measureStackContent:targetSize];
break;
}
case DoricVLayout: {
[self measureVLayoutContent:targetSize];
break;
}
case DoricHLayout: {
[self measureHLayoutContent:targetSize];
break;
}
default: {
[self measureUndefinedContent:targetSize];
break;
}
}
} }
@end
- (void)layout {
switch (self.layoutType) {
case DoricStack: {
[self layoutStack];
break;
}
case DoricVLayout: {
[self layoutVLayout];
break;
}
case DoricHLayout: {
[self layoutHLayout];
break;
}
default: {
break;
}
}
}
@interface DoricStackView () - (void)setFrame {
@end [self.view.subviews forEach:^(__kindof UIView *obj) {
[obj.doricLayout setFrame];
}];
self.view.width = self.measuredWidth;
self.view.height = self.measuredHeight;
self.view.x = self.measuredX;
self.view.y = self.measuredY;
}
@implementation DoricStackView - (void)measureUndefinedContent:(CGSize)targetSize {
CGSize measuredSize = [self.view sizeThatFits:targetSize];
if (self.widthSpec == DoricLayoutFit) {
self.measuredWidth = measuredSize.width + self.paddingLeft + self.paddingRight;
}
if (self.heightSpec == DoricLayoutFit) {
self.measuredHeight = measuredSize.height + self.paddingTop + self.paddingBottom;
}
}
- (CGSize)sizeThatFits:(CGSize)size { - (CGFloat)takenWidth {
CGFloat contentWidth = 0; return self.measuredWidth + self.marginLeft + self.marginRight;
CGFloat contentHeight = 0; }
for (UIView *child in self.subviews) {
if (child.isHidden) { - (CGFloat)takenHeight {
return self.measuredHeight + self.marginTop + self.marginBottom;
}
- (void)measureStackContent:(CGSize)targetSize {
CGFloat contentWidth = 0, contentHeight = 0;
for (__kindof UIView *subview in self.view.subviews) {
DoricLayout *layout = subview.doricLayout;
if (layout.disabled) {
continue; continue;
} }
DoricLayoutConfig *childConfig = child.layoutConfig; [layout measure:targetSize];
if (!childConfig) { contentWidth = MAX(contentWidth, layout.takenWidth);
childConfig = [DoricLayoutConfig new]; contentHeight = MAX(contentHeight, layout.takenHeight);
}
CGSize childSize;
if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) {
childSize = [child measureSize:CGSizeMake(size.width, size.height)];
} else {
childSize = child.bounds.size;
}
contentWidth = MAX(contentWidth, childSize.width + childConfig.margin.left + childConfig.margin.right);
contentHeight = MAX(contentHeight, childSize.height + childConfig.margin.top + childConfig.margin.bottom);
} }
if (self.widthSpec == DoricLayoutFit) {
self.measuredWidth = contentWidth + self.paddingLeft + self.paddingRight;
}
if (self.heightSpec == DoricLayoutFit) {
self.measuredHeight = contentHeight + self.paddingTop + self.paddingBottom;
}
self.contentWidth = contentWidth; self.contentWidth = contentWidth;
self.contentHeight = contentHeight; self.contentHeight = contentHeight;
return CGSizeMake(contentWidth, contentHeight);
} }
- (void)layoutSelf:(CGSize)targetSize { - (void)measureVLayoutContent:(CGSize)targetSize {
self.width = targetSize.width; CGFloat contentWidth = 0, contentHeight = 0;
self.height = targetSize.height; BOOL had = NO;
DoricPadding padding = self.padding; for (__kindof UIView *subview in self.view.subviews) {
DoricLayout *layout = subview.doricLayout;
for (UIView *child in self.subviews) { if (layout.disabled) {
if (child.isHidden) {
continue; continue;
} }
if (!CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { had = YES;
[layout measure:CGSizeMake(targetSize.width, targetSize.height - contentHeight)];
contentWidth = MAX(contentWidth, layout.takenWidth);
contentHeight += layout.takenHeight + self.spacing;
}
if (had) {
contentHeight -= self.spacing;
}
if (self.widthSpec == DoricLayoutFit) {
self.measuredWidth = contentWidth + self.paddingLeft + self.paddingRight;
}
if (self.heightSpec == DoricLayoutFit) {
self.measuredHeight = contentHeight + self.paddingTop + self.paddingBottom;
}
self.contentWidth = contentWidth;
self.contentHeight = contentHeight;
}
- (void)measureHLayoutContent:(CGSize)targetSize {
CGFloat contentWidth = 0, contentHeight = 0;
BOOL had = NO;
for (__kindof UIView *subview in self.view.subviews) {
DoricLayout *layout = subview.doricLayout;
if (layout.disabled) {
continue; continue;
} }
DoricLayoutConfig *childConfig = child.layoutConfig; had = YES;
if (!childConfig) { [layout measure:CGSizeMake(targetSize.width - contentWidth, targetSize.height)];
childConfig = [DoricLayoutConfig new]; contentWidth += layout.takenWidth + self.spacing;
} contentHeight = MAX(contentHeight, layout.takenHeight);
CGSize size = [child measureSize:CGSizeMake( }
targetSize.width - padding.left - padding.right,
targetSize.height - padding.top - padding.bottom)];
[child layoutSelf:size];
DoricGravity gravity = childConfig.alignment;
CGPoint point = child.frame.origin; if (had) {
contentWidth -= self.spacing;
}
if (self.widthSpec == DoricLayoutFit) {
self.measuredWidth = contentWidth + self.paddingLeft + self.paddingRight;
}
if (self.heightSpec == DoricLayoutFit) {
self.measuredHeight = contentHeight + self.paddingTop + self.paddingBottom;
}
self.contentWidth = contentWidth;
self.contentHeight = contentHeight;
}
- (void)layoutStack {
for (__kindof UIView *subview in self.view.subviews) {
DoricLayout *layout = subview.doricLayout;
if (layout.disabled) {
continue;
}
[layout layout];
DoricGravity gravity = layout.alignment;
if ((gravity & DoricGravityLeft) == DoricGravityLeft) { if ((gravity & DoricGravityLeft) == DoricGravityLeft) {
point.x = padding.left; layout.measuredX = self.paddingLeft;
} else if ((gravity & DoricGravityRight) == DoricGravityRight) { } else if ((gravity & DoricGravityRight) == DoricGravityRight) {
point.x = targetSize.width - padding.right - child.width; layout.measuredX = self.measuredWidth - self.paddingRight - layout.measuredWidth;
} else if ((gravity & DoricGravityCenterX) == DoricGravityCenterX) { } else if ((gravity & DoricGravityCenterX) == DoricGravityCenterX) {
point.x = targetSize.width / 2 - child.width / 2; layout.measuredX = self.measuredWidth / 2 - layout.measuredWidth / 2;
} else { } else {
if (childConfig.margin.left || childConfig.margin.right) { if (layout.marginLeft || layout.marginRight) {
point.x = padding.left; layout.measuredX = self.paddingLeft;
} else {
layout.measuredX = layout.x;
} }
} }
if ((gravity & DoricGravityTOP) == DoricGravityTOP) { if ((gravity & DoricGravityTop) == DoricGravityTop) {
point.y = padding.top; layout.measuredY = self.paddingTop;
} else if ((gravity & DoricGravityBottom) == DoricGravityBottom) { } else if ((gravity & DoricGravityBottom) == DoricGravityBottom) {
point.y = targetSize.height - padding.bottom - child.height; layout.measuredY = self.measuredHeight - self.paddingBottom - layout.measuredHeight;
} else if ((gravity & DoricGravityCenterY) == DoricGravityCenterY) { } else if ((gravity & DoricGravityCenterY) == DoricGravityCenterY) {
point.y = targetSize.height / 2 - child.height / 2; layout.measuredY = self.measuredHeight / 2 - layout.measuredHeight / 2;
} else { } else {
if (childConfig.margin.top || childConfig.margin.bottom) { if (layout.marginTop || layout.marginBottom) {
point.y = padding.top; layout.measuredY = self.paddingTop;
} else {
layout.measuredY = layout.y;
} }
} }
if (!gravity) { if (!gravity) {
gravity = DoricGravityLeft | DoricGravityTOP; gravity = DoricGravityLeft | DoricGravityTop;
} }
if (childConfig.margin.left && !((gravity & DoricGravityRight) == DoricGravityRight)) { if (layout.marginLeft && !((gravity & DoricGravityRight) == DoricGravityRight)) {
point.x += childConfig.margin.left; layout.measuredX += layout.marginLeft;
} }
if (childConfig.margin.right && !((gravity & DoricGravityLeft) == DoricGravityLeft)) { if (layout.marginRight && !((gravity & DoricGravityLeft) == DoricGravityLeft)) {
point.x -= childConfig.margin.right; layout.measuredX -= layout.marginRight;
} }
if (childConfig.margin.top && !((gravity & DoricGravityBottom) == DoricGravityBottom)) { if (layout.marginTop && !((gravity & DoricGravityBottom) == DoricGravityBottom)) {
point.y += childConfig.margin.top; layout.measuredY += layout.marginTop;
} }
if (childConfig.margin.bottom && !((gravity & DoricGravityTOP) == DoricGravityTOP)) { if (layout.marginBottom && !((gravity & DoricGravityTop) == DoricGravityTop)) {
point.y -= childConfig.margin.bottom; layout.measuredY -= layout.marginBottom;
}
if (point.x != child.x) {
child.x = point.x;
}
if (point.y != child.y) {
child.y = point.y;
} }
} }
} }
@end
@implementation DoricLinearView - (void)layoutVLayout {
@end CGFloat yStart = self.paddingTop;
if ((self.gravity & DoricGravityTop) == DoricGravityTop) {
@implementation DoricVLayoutView yStart = self.paddingTop;
- (CGSize)sizeThatFits:(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;
if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) {
childSize = [child measureSize:CGSizeMake(size.width, size.height - contentHeight)];
} else {
childSize = child.bounds.size;
}
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)layoutSelf:(CGSize)targetSize {
self.width = targetSize.width;
self.height = targetSize.height;
DoricPadding padding = self.padding;
CGFloat yStart = padding.top;
if ((self.gravity & DoricGravityTOP) == DoricGravityTOP) {
yStart = padding.top;
} else if ((self.gravity & DoricGravityBottom) == DoricGravityBottom) { } else if ((self.gravity & DoricGravityBottom) == DoricGravityBottom) {
yStart = targetSize.height - self.contentHeight - padding.bottom; yStart = self.measuredHeight - self.contentHeight - self.paddingBottom;
} else if ((self.gravity & DoricGravityCenterY) == DoricGravityCenterY) { } else if ((self.gravity & DoricGravityCenterY) == DoricGravityCenterY) {
yStart = (targetSize.height - self.contentHeight - padding.top - padding.bottom) / 2 + padding.top; yStart = (self.measuredHeight - self.contentHeight - self.paddingTop - self.paddingBottom) / 2 + self.paddingTop;
} }
CGFloat remain = targetSize.height - self.contentHeight - padding.top - padding.bottom; for (UIView *child in self.view.subviews) {
for (UIView *child in self.subviews) { DoricLayout *layout = child.doricLayout;
if (child.isHidden) { if (layout.disabled) {
continue; continue;
} }
if (!CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { [layout layout];
continue; DoricGravity gravity = layout.alignment | self.gravity;
}
DoricLayoutConfig *childConfig = child.layoutConfig;
if (!childConfig) {
childConfig = [DoricLayoutConfig new];
}
CGSize size = [child measureSize:CGSizeMake(
targetSize.width - padding.left - padding.right,
targetSize.height - yStart - padding.bottom)];
if (childConfig.weight) {
size.height += remain / self.contentWeight * childConfig.weight;
}
[child layoutSelf:size];
DoricGravity gravity = childConfig.alignment | self.gravity;
CGPoint point = child.frame.origin;
if ((gravity & DoricGravityLeft) == DoricGravityLeft) { if ((gravity & DoricGravityLeft) == DoricGravityLeft) {
point.x = padding.left; layout.measuredX = self.paddingLeft;
} else if ((gravity & DoricGravityRight) == DoricGravityRight) { } else if ((gravity & DoricGravityRight) == DoricGravityRight) {
point.x = targetSize.width - padding.right - child.width; layout.measuredX = self.measuredWidth - self.paddingRight - layout.measuredWidth;
} else if ((gravity & DoricGravityCenterX) == DoricGravityCenterX) { } else if ((gravity & DoricGravityCenterX) == DoricGravityCenterX) {
point.x = targetSize.width / 2 - child.width / 2; layout.measuredX = self.measuredWidth / 2 - layout.measuredWidth / 2;
} else { } else {
point.x = padding.left; layout.measuredX = self.paddingLeft;
} }
if (!gravity) { if (!gravity) {
gravity = DoricGravityLeft; gravity = DoricGravityLeft;
} }
if (childConfig.margin.left && !((gravity & DoricGravityRight) == DoricGravityRight)) { if (layout.marginLeft && !((gravity & DoricGravityRight) == DoricGravityRight)) {
point.x += childConfig.margin.left; layout.measuredX += layout.marginLeft;
} }
if (childConfig.margin.right && !((gravity & DoricGravityLeft) == DoricGravityLeft)) { if (layout.marginRight && !((gravity & DoricGravityLeft) == DoricGravityLeft)) {
point.x -= childConfig.margin.right; layout.measuredX -= layout.marginRight;
}
if (point.x != child.x) {
child.x = point.x;
}
if (childConfig.margin.top) {
yStart += childConfig.margin.top;
}
child.top = yStart;
yStart = child.bottom + self.space;
if (childConfig.margin.bottom) {
yStart += childConfig.margin.bottom;
} }
layout.measuredY = yStart + layout.marginTop;
yStart += self.spacing + layout.takenHeight;
} }
} }
@end
@implementation DoricHLayoutView - (void)layoutHLayout {
- (CGSize)sizeThatFits:(CGSize)size { CGFloat xStart = self.paddingLeft;
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;
if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) {
childSize = [child measureSize:CGSizeMake(size.width - contentWidth, size.height)];
} else {
childSize = child.bounds.size;
}
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;
}
if (self.subviews.count > 0) {
contentWidth -= self.space;
}
self.contentWidth = contentWidth;
self.contentHeight = contentHeight;
self.contentWeight = contentWeight;
if (contentWeight) {
contentWidth = size.width;
}
return CGSizeMake(contentWidth, contentHeight);
}
- (void)layoutSelf:(CGSize)targetSize {
self.width = targetSize.width;
self.height = targetSize.height;
DoricPadding padding = self.padding;
CGFloat xStart = padding.left;
if ((self.gravity & DoricGravityLeft) == DoricGravityLeft) { if ((self.gravity & DoricGravityLeft) == DoricGravityLeft) {
xStart = padding.left; xStart = self.paddingLeft;
} else if ((self.gravity & DoricGravityRight) == DoricGravityRight) { } else if ((self.gravity & DoricGravityRight) == DoricGravityRight) {
xStart = targetSize.width - self.contentWidth - padding.right; xStart = self.measuredWidth - self.contentWidth - self.paddingRight;
} else if ((self.gravity & DoricGravityCenterX) == DoricGravityCenterX) { } else if ((self.gravity & DoricGravityCenterX) == DoricGravityCenterX) {
xStart = (targetSize.width - self.contentWidth - padding.left - padding.right) / 2 + padding.left; xStart = (self.measuredWidth - self.contentWidth - self.paddingLeft - self.paddingRight) / 2 + self.paddingLeft;
} }
CGFloat remain = targetSize.width - self.contentWidth - padding.left - padding.right; for (UIView *child in self.view.subviews) {
for (UIView *child in self.subviews) { DoricLayout *layout = child.doricLayout;
if (child.isHidden) { if (layout.disabled) {
continue; continue;
} }
if (!CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { [layout layout];
continue;
}
DoricLayoutConfig *childConfig = child.layoutConfig;
if (!childConfig) {
childConfig = [DoricLayoutConfig new];
}
CGSize size = [child measureSize:CGSizeMake( DoricGravity gravity = layout.alignment | self.gravity;
targetSize.width - xStart - padding.right, if ((gravity & DoricGravityTop) == DoricGravityTop) {
targetSize.height - padding.top - padding.bottom)]; layout.measuredY = self.paddingTop;
if (childConfig.weight) {
size.width += remain / self.contentWeight * childConfig.weight;
}
[child layoutSelf:size];
DoricGravity gravity = childConfig.alignment | self.gravity;
CGPoint point = child.frame.origin;
if ((gravity & DoricGravityTOP) == DoricGravityTOP) {
point.y = padding.top;
} else if ((gravity & DoricGravityBottom) == DoricGravityBottom) { } else if ((gravity & DoricGravityBottom) == DoricGravityBottom) {
point.y = targetSize.height - padding.bottom - child.height; layout.measuredY = self.measuredHeight - self.paddingBottom - child.height;
} else if ((gravity & DoricGravityCenterY) == DoricGravityCenterY) { } else if ((gravity & DoricGravityCenterY) == DoricGravityCenterY) {
point.y = targetSize.height / 2 - child.height / 2; layout.measuredY = self.measuredHeight / 2 - layout.measuredHeight / 2;
} else { } else {
point.y = padding.top; layout.measuredY = self.paddingTop;
} }
if (!gravity) { if (!gravity) {
gravity = DoricGravityTOP; gravity = DoricGravityTop;
} }
if (childConfig.margin.top && !((gravity & DoricGravityBottom) == DoricGravityBottom)) { if (layout.marginTop && !((gravity & DoricGravityBottom) == DoricGravityBottom)) {
point.y += childConfig.margin.top; layout.measuredY += layout.marginTop;
} }
if (childConfig.margin.bottom && !((gravity & DoricGravityTOP) == DoricGravityTOP)) { if (layout.marginBottom && !((gravity & DoricGravityTop) == DoricGravityTop)) {
point.y -= childConfig.margin.bottom; layout.measuredY -= layout.marginBottom;
}
if (point.y != child.y) {
child.y = point.y;
}
if (childConfig.margin.left) {
xStart += childConfig.margin.left;
}
child.left = xStart;
xStart = child.right + self.space;
if (childConfig.margin.right) {
xStart += childConfig.margin.right;
} }
layout.measuredX = xStart + layout.marginLeft;
xStart += self.spacing + layout.takenWidth;
} }
} }
@end @end

View File

@ -23,7 +23,7 @@
@interface DoricListItemNode () @interface DoricListItemNode ()
@end @end
@interface DoricListItemView : DoricStackView @interface DoricListItemView : UIView
@end @end
@implementation DoricListItemView @implementation DoricListItemView
@ -43,7 +43,7 @@ - (void)initWithSuperNode:(DoricSuperNode *)superNode {
self.reusable = YES; self.reusable = YES;
} }
- (DoricStackView *)build { - (DoricListItemView *)build {
return [DoricListItemView new]; return [DoricListItemView new];
} }
@end @end

View File

@ -35,24 +35,24 @@ @interface DoricTableView : UITableView
@end @end
@implementation DoricTableView @implementation DoricTableView
- (CGSize)sizeThatFits:(CGSize)size { //- (CGSize)sizeThatFits:(CGSize)size {
if (self.subviews.count > 0) { // if (self.subviews.count > 0) {
CGFloat width = size.width; // CGFloat width = size.width;
CGFloat height = 0; // CGFloat height = 0;
//
for (UIView *child in self.subviews) { // for (UIView *child in self.subviews) {
CGSize childSize = [child measureSize:size]; // CGSize childSize = [child measureSize:size];
width = MAX(childSize.width, width); // width = MAX(childSize.width, width);
height += childSize.height; // height += childSize.height;
} // }
return CGSizeMake(width, MAX(height, size.height)); // return CGSizeMake(width, MAX(height, size.height));
} // }
return size; // return size;
} //}
//
- (void)layoutSelf:(CGSize)targetSize { //- (void)layoutSelf:(CGSize)targetSize {
[super layoutSelf:targetSize]; // [super layoutSelf:targetSize];
} //}
@end @end
@ -158,9 +158,9 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
DoricListItemNode *node = cell.doricListItemNode; DoricListItemNode *node = cell.doricListItemNode;
node.viewId = model[@"id"]; node.viewId = model[@"id"];
[node blend:props]; [node blend:props];
CGSize size = [node.view measureSize:CGSizeMake(tableView.width, tableView.height)]; // CGSize size = [node.view measureSize:CGSizeMake(tableView.width, tableView.height)];
[node.view layoutSelf:size]; // [node.view layoutSelf:size];
[self callItem:position height:size.height]; // [self callItem:position height:size.height];
return cell; return cell;
} }

View File

@ -25,27 +25,27 @@ @interface DoricNestedSliderView : UIScrollView
@end @end
@implementation DoricNestedSliderView @implementation DoricNestedSliderView
- (CGSize)sizeThatFits:(CGSize)size { //- (CGSize)sizeThatFits:(CGSize)size {
if (self.subviews.count > 0) { // if (self.subviews.count > 0) {
CGFloat width = size.width; // CGFloat width = size.width;
CGFloat height = size.height; // CGFloat height = size.height;
for (UIView *child in self.subviews) { // for (UIView *child in self.subviews) {
CGSize childSize = [child measureSize:size]; // CGSize childSize = [child measureSize:size];
width = MAX(childSize.width, width); // width = MAX(childSize.width, width);
height = MAX(childSize.height, height); // height = MAX(childSize.height, height);
} // }
return CGSizeMake(width, height); // return CGSizeMake(width, height);
} // }
return size; // return size;
} //}
//
- (void)layoutSelf:(CGSize)targetSize { //- (void)layoutSelf:(CGSize)targetSize {
[super layoutSelf:targetSize]; // [super layoutSelf:targetSize];
[self.subviews forEachIndexed:^(__kindof UIView *obj, NSUInteger idx) { // [self.subviews forEachIndexed:^(__kindof UIView *obj, NSUInteger idx) {
obj.left = idx * self.width; // obj.left = idx * self.width;
}]; // }];
[self setContentSize:CGSizeMake(self.subviews.count * self.width, self.height)]; // [self setContentSize:CGSizeMake(self.subviews.count * self.width, self.height)];
} //}
@end @end
@interface DoricNestedSliderNode () <UIScrollViewDelegate> @interface DoricNestedSliderNode () <UIScrollViewDelegate>

View File

@ -22,12 +22,12 @@
#import "DoricStackNode.h" #import "DoricStackNode.h"
@interface DoricRootView : DoricStackView @interface DoricRootView : UIView
@property(nonatomic, strong) void (^frameChangedBlock)(CGSize oldSize, CGSize newSize); @property(nonatomic, strong) void (^frameChangedBlock)(CGSize oldSize, CGSize newSize);
@end @end
@interface DoricRootNode : DoricStackNode @interface DoricRootNode : DoricStackNode
- (void)setupRootView:(DoricStackView *)view; - (void)setupRootView:(UIView *)view;
@end @end

View File

@ -35,12 +35,12 @@ - (instancetype)init {
return self; return self;
} }
- (void)layoutSelf:(CGSize)targetSize { - (void)layoutSubviews {
[super layoutSelf:targetSize]; [super layoutSubviews];
if (!CGSizeEqualToSize(self.currentSize, targetSize) && self.frameChangedBlock) { if (!CGSizeEqualToSize(self.currentSize, self.frame.size) && self.frameChangedBlock) {
self.frameChangedBlock(self.currentSize, targetSize); self.frameChangedBlock(self.currentSize, self.frame.size);
} }
self.currentSize = targetSize; self.currentSize = self.frame.size;
} }
- (void)setX:(CGFloat)x { - (void)setX:(CGFloat)x {
@ -54,11 +54,12 @@ - (void)setY:(CGFloat)y {
@end @end
@implementation DoricRootNode @implementation DoricRootNode
- (void)setupRootView:(DoricStackView *)view { - (void)setupRootView:(UIView *)view {
view.doricLayout.layoutType = DoricStack;
self.view = view; self.view = view;
} }
- (void)requestLayout { - (void)requestLayout {
[self.view setNeedsLayout]; [self.view.doricLayout apply];
} }
@end @end

View File

@ -27,25 +27,25 @@
@implementation DoricScrollView @implementation DoricScrollView
- (void)setContentView:(UIView *)contentView { //- (void)setContentView:(UIView *)contentView {
if (_contentView) { // if (_contentView) {
[_contentView removeFromSuperview]; // [_contentView removeFromSuperview];
} // }
_contentView = contentView; // _contentView = contentView;
[self addSubview:contentView]; // [self addSubview:contentView];
} //}
//
- (CGSize)sizeThatFits:(CGSize)size { //- (CGSize)sizeThatFits:(CGSize)size {
if (self.contentView) { // if (self.contentView) {
return [self.contentView measureSize:size]; // return [self.contentView measureSize:size];
} // }
return CGSizeZero; // return CGSizeZero;
} //}
//
- (void)layoutSelf:(CGSize)targetSize { //- (void)layoutSelf:(CGSize)targetSize {
[super layoutSelf:targetSize]; // [super layoutSelf:targetSize];
[self setContentSize:self.contentView.frame.size]; // [self setContentSize:self.contentView.frame.size];
} //}
@end @end

View File

@ -21,7 +21,7 @@
// //
#import "DoricSlideItemNode.h" #import "DoricSlideItemNode.h"
@interface DoricSlideItemView : DoricStackView @interface DoricSlideItemView : UIView
@end @end
@implementation DoricSlideItemView @implementation DoricSlideItemView
@ -45,7 +45,7 @@ - (void)initWithSuperNode:(DoricSuperNode *)superNode {
self.view.clipsToBounds = YES; self.view.clipsToBounds = YES;
} }
- (DoricStackView *)build { - (DoricSlideItemView *)build {
return [DoricSlideItemView new]; return [DoricSlideItemView new];
} }
@end @end

View File

@ -44,24 +44,24 @@ @interface DoricSliderView : UICollectionView
@end @end
@implementation DoricSliderView @implementation DoricSliderView
- (CGSize)sizeThatFits:(CGSize)size { //- (CGSize)sizeThatFits:(CGSize)size {
if (self.subviews.count > 0) { // if (self.subviews.count > 0) {
CGFloat width = size.width; // CGFloat width = size.width;
CGFloat height = size.height; // CGFloat height = size.height;
for (UIView *child in self.subviews) { // for (UIView *child in self.subviews) {
CGSize childSize = [child measureSize:size]; // CGSize childSize = [child measureSize:size];
width = MAX(childSize.width, width); // width = MAX(childSize.width, width);
height = MAX(childSize.height, height); // height = MAX(childSize.height, height);
} // }
return CGSizeMake(width, height); // return CGSizeMake(width, height);
} // }
return size; // return size;
} //}
//
- (void)layoutSelf:(CGSize)targetSize { //- (void)layoutSelf:(CGSize)targetSize {
[super layoutSelf:targetSize]; // [super layoutSelf:targetSize];
[self reloadData]; // [self reloadData];
} //}
@end @end
@implementation DoricSliderNode @implementation DoricSliderNode
@ -143,8 +143,8 @@ - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collection
DoricSlideItemNode *node = cell.doricSlideItemNode; DoricSlideItemNode *node = cell.doricSlideItemNode;
node.viewId = model[@"id"]; node.viewId = model[@"id"];
[node blend:props]; [node blend:props];
CGSize size = [node.view measureSize:CGSizeMake(collectionView.width, collectionView.height)]; // CGSize size = [node.view measureSize:CGSizeMake(collectionView.width, collectionView.height)];
[node.view layoutSelf:size]; // [node.view layoutSelf:size];
return cell; return cell;
} }

View File

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

View File

@ -21,14 +21,13 @@
// //
#import "DoricStackNode.h" #import "DoricStackNode.h"
#import "DoricExtensions.h"
@implementation DoricStackNode @implementation DoricStackNode
- (DoricStackView *)build { - (UIView *)build {
return [DoricStackView new]; return [[UIView new] also:^(UIView *it) {
} it.doricLayout.layoutType = DoricStack;
}];
- (void)blendView:(DoricStackView *)view forPropName:(NSString *)name propValue:(id)prop {
[super blendView:view forPropName:name propValue:prop];
} }
@end @end

View File

@ -23,8 +23,6 @@
@interface DoricSuperNode<V:UIView *> : DoricViewNode<V> @interface DoricSuperNode<V:UIView *> : DoricViewNode<V>
@property(nonatomic, assign) BOOL reusable; @property(nonatomic, assign) BOOL reusable;
- (DoricLayoutConfig *)generateDefaultLayoutParams;
- (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutConfig; - (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutConfig;
- (void)blendSubNode:(NSDictionary *)subModel; - (void)blendSubNode:(NSDictionary *)subModel;

View File

@ -92,37 +92,7 @@ - (void)recursiveMixin:(NSDictionary *)srcModel to:(NSMutableDictionary *)target
} }
- (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutConfig { - (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutConfig {
DoricLayoutConfig *params = subNode.layoutConfig; [subNode blendLayoutConfig:layoutConfig];
[layoutConfig[@"widthSpec"] also:^(NSNumber *it) {
if (it) {
params.widthSpec = (DoricLayoutSpec) [it integerValue];
}
}];
[layoutConfig[@"heightSpec"] also:^(NSNumber *it) {
if (it) {
params.heightSpec = (DoricLayoutSpec) [it integerValue];
}
}];
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];
}
NSNumber *weight = layoutConfig[@"weight"];
if (weight) {
params.weight = (DoricGravity) [weight integerValue];
}
} }
- (void)blendSubNode:(NSDictionary *)subModel { - (void)blendSubNode:(NSDictionary *)subModel {
@ -130,8 +100,8 @@ - (void)blendSubNode:(NSDictionary *)subModel {
NSStringFromSelector(_cmd)); NSStringFromSelector(_cmd));
} }
- (DoricLayoutConfig *)generateDefaultLayoutParams { - (DoricLayout *)generateDefaultLayoutParams {
DoricLayoutConfig *params = [[DoricLayoutConfig alloc] init]; DoricLayout *params = [[DoricLayout alloc] init];
return params; return params;
} }

View File

@ -32,20 +32,13 @@ @interface DoricTextView : UILabel
@implementation DoricTextView @implementation DoricTextView
- (void)drawTextInRect:(CGRect)rect { - (void)drawTextInRect:(CGRect)rect {
[super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.padding)]; [super drawTextInRect:UIEdgeInsetsInsetRect(
} rect,
UIEdgeInsetsMake(
- (CGSize)measureSize:(CGSize)targetSize { self.doricLayout.paddingTop,
CGSize measuredSize = [super measureSize:targetSize]; self.doricLayout.paddingLeft,
CGFloat measuredWidth = measuredSize.width; self.doricLayout.paddingBottom,
CGFloat measuredHeight = measuredSize.height; self.doricLayout.paddingRight))];
if (self.maxWidth >= 0) {
measuredWidth = MIN(self.maxWidth, measuredSize.width);
}
if (self.maxHeight >= 0) {
measuredHeight = MIN(self.maxHeight, measuredSize.height);
}
return CGSizeMake(measuredWidth, measuredHeight);
} }
@end @end

View File

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

View File

@ -21,18 +21,21 @@
// //
#import "DoricVLayoutNode.h" #import "DoricVLayoutNode.h"
#import "DoricExtensions.h"
@implementation DoricVLayoutNode @implementation DoricVLayoutNode
- (DoricVLayoutView *)build { - (UIView *)build {
return [DoricVLayoutView new]; return [[UIView new] also:^(UIView *it) {
it.doricLayout.layoutType = DoricVLayout;
}];
} }
- (void)blendView:(DoricVLayoutView *)view forPropName:(NSString *)name propValue:(id)prop { - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([name isEqualToString:@"gravity"]) { if ([name isEqualToString:@"gravity"]) {
view.gravity = (DoricGravity) [(NSNumber *) prop integerValue]; view.doricLayout.gravity = (DoricGravity) [(NSNumber *) prop integerValue];
} else if ([name isEqualToString:@"space"]) { } else if ([name isEqualToString:@"space"]) {
view.space = [(NSNumber *) prop floatValue]; view.doricLayout.spacing = [(NSNumber *) prop floatValue];
} else { } else {
[super blendView:view forPropName:name propValue:prop]; [super blendView:view forPropName:name propValue:prop];
} }

View File

@ -36,8 +36,6 @@
@property(nonatomic, copy) NSString *type; @property(nonatomic, copy) NSString *type;
@property(nonatomic, readonly) DoricLayoutConfig *layoutConfig;
@property(nonatomic, readonly) NSArray<NSString *> *idList; @property(nonatomic, readonly) NSArray<NSString *> *idList;
- (void)initWithSuperNode:(DoricSuperNode *)superNode; - (void)initWithSuperNode:(DoricSuperNode *)superNode;
@ -53,4 +51,8 @@
+ (__kindof DoricViewNode *)create:(DoricContext *)context withType:(NSString *)type; + (__kindof DoricViewNode *)create:(DoricContext *)context withType:(NSString *)type;
- (void)requestLayout; - (void)requestLayout;
- (void)blendLayoutConfig:(NSDictionary *)params;
- (void)afterBlended:(NSDictionary *)props;
@end @end

View File

@ -20,6 +20,7 @@
// Created by pengfei.zhou on 2019/7/30. // Created by pengfei.zhou on 2019/7/30.
// //
#import <DoricCore/DoricExtensions.h>
#import "DoricViewNode.h" #import "DoricViewNode.h"
#import "DoricUtil.h" #import "DoricUtil.h"
#import "DoricGroupNode.h" #import "DoricGroupNode.h"
@ -121,13 +122,7 @@ - (void)initWithSuperNode:(DoricSuperNode *)superNode {
((DoricSuperNode *) self).reusable = superNode.reusable; ((DoricSuperNode *) self).reusable = superNode.reusable;
} }
self.superNode = superNode; self.superNode = superNode;
self.view = [[self build] also:^(UIView *it) { self.view = [self build];
it.layoutConfig = [superNode generateDefaultLayoutParams];
}];
}
- (DoricLayoutConfig *)layoutConfig {
return self.view.layoutConfig;
} }
- (UIView *)build { - (UIView *)build {
@ -135,7 +130,6 @@ - (UIView *)build {
} }
- (void)blend:(NSDictionary *)props { - (void)blend:(NSDictionary *)props {
self.view.layoutConfig = self.layoutConfig;
for (NSString *key in props) { for (NSString *key in props) {
id value = props[key]; id value = props[key];
if (!value || [value isKindOfClass:[NSNull class]]) { if (!value || [value isKindOfClass:[NSNull class]]) {
@ -144,9 +138,14 @@ - (void)blend:(NSDictionary *)props {
[self blendView:self.view forPropName:key propValue:value]; [self blendView:self.view forPropName:key propValue:value];
} }
[self transformProperties]; [self transformProperties];
[self afterBlended:props];
[self requestLayout];
self.gradientLayer.frame = CGRectMake(0, 0, self.view.width, self.view.height); self.gradientLayer.frame = CGRectMake(0, 0, self.view.width, self.view.height);
} }
- (void)afterBlended:(NSDictionary *)props {
}
- (void)transformProperties { - (void)transformProperties {
CGAffineTransform transform = CGAffineTransformIdentity; CGAffineTransform transform = CGAffineTransformIdentity;
if (self.translationX || self.translationY) { if (self.translationX || self.translationY) {
@ -171,19 +170,13 @@ - (void)transformProperties {
- (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop { - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([name isEqualToString:@"width"]) { if ([name isEqualToString:@"width"]) {
NSNumber *width = (NSNumber *) prop; view.doricLayout.width = [prop floatValue];
if ([width floatValue] >= 0) {
view.width = [width floatValue];
}
} else if ([name isEqualToString:@"height"]) { } else if ([name isEqualToString:@"height"]) {
NSNumber *height = (NSNumber *) prop; view.doricLayout.height = [prop floatValue];
if ([height floatValue] >= 0) {
view.height = [height floatValue];
}
} else if ([name isEqualToString:@"x"]) { } else if ([name isEqualToString:@"x"]) {
view.x = [prop floatValue]; view.doricLayout.x = [prop floatValue];
} else if ([name isEqualToString:@"y"]) { } else if ([name isEqualToString:@"y"]) {
view.y = [prop floatValue]; view.doricLayout.y = [prop floatValue];
} else if ([name isEqualToString:@"backgroundColor"]) { } else if ([name isEqualToString:@"backgroundColor"]) {
if ([prop isKindOfClass:[NSNumber class]]) { if ([prop isKindOfClass:[NSNumber class]]) {
view.backgroundColor = DoricColor(prop); view.backgroundColor = DoricColor(prop);
@ -298,19 +291,20 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
} else if ([name isEqualToString:@"rotation"]) { } else if ([name isEqualToString:@"rotation"]) {
self.rotation = prop; self.rotation = prop;
} else if ([name isEqualToString:@"padding"]) { } else if ([name isEqualToString:@"padding"]) {
DoricPadding padding; view.doricLayout.paddingLeft = 0;
padding.left = padding.right = padding.top = padding.bottom = 0; view.doricLayout.paddingRight = 0;
view.doricLayout.paddingTop = 0;
view.doricLayout.paddingBottom = 0;
if ([prop isKindOfClass:[NSDictionary class]]) { if ([prop isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = prop; NSDictionary *dictionary = prop;
padding.left = [dictionary[@"left"] floatValue]; view.doricLayout.paddingLeft = [dictionary[@"left"] floatValue];
padding.right = [dictionary[@"right"] floatValue]; view.doricLayout.paddingRight = [dictionary[@"right"] floatValue];
padding.top = [dictionary[@"top"] floatValue]; view.doricLayout.paddingTop = [dictionary[@"top"] floatValue];
padding.bottom = [dictionary[@"bottom"] floatValue]; view.doricLayout.paddingBottom = [dictionary[@"bottom"] floatValue];
} }
self.view.padding = padding;
} else if ([name isEqualToString:@"hidden"]) { } else if ([name isEqualToString:@"hidden"]) {
self.view.hidden = [prop boolValue]; self.view.hidden = [prop boolValue];
[self.view.superview setNeedsLayout]; self.view.doricLayout.disabled = [prop boolValue];
} 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);
} }
@ -380,38 +374,26 @@ - (NSDictionary *)getLocationOnScreen {
} }
- (void)blendLayoutConfig:(NSDictionary *)params { - (void)blendLayoutConfig:(NSDictionary *)params {
if (!self.layoutConfig) {
self.view.layoutConfig = [DoricLayoutConfig new];
}
[params[@"widthSpec"] also:^(NSNumber *it) { [params[@"widthSpec"] also:^(NSNumber *it) {
if (it) { self.view.doricLayout.widthSpec = (DoricLayoutSpec) [it integerValue];
self.layoutConfig.widthSpec = (DoricLayoutSpec) [it integerValue];
}
}]; }];
[params[@"heightSpec"] also:^(NSNumber *it) { [params[@"heightSpec"] also:^(NSNumber *it) {
if (it) { self.view.doricLayout.heightSpec = (DoricLayoutSpec) [it integerValue];
self.layoutConfig.heightSpec = (DoricLayoutSpec) [it integerValue]; }];
} [params[@"margin"] also:^(NSDictionary *it) {
self.view.doricLayout.marginLeft = [it[@"left"] floatValue];
self.view.doricLayout.marginTop = [it[@"top"] floatValue];
self.view.doricLayout.marginRight = [it[@"right"] floatValue];
self.view.doricLayout.marginBottom = [it[@"bottom"] floatValue];
}];
[params[@"alignment"] also:^(NSNumber *it) {
self.view.doricLayout.alignment = (DoricGravity) [it integerValue];
}];
[params[@"weight"] also:^(NSNumber *it) {
self.view.doricLayout.weight = (DoricGravity) [it integerValue];
}]; }];
NSDictionary *margin = params[@"margin"];
if (margin) {
self.layoutConfig.margin = DoricMarginMake(
[(NSNumber *) margin[@"left"] floatValue],
[(NSNumber *) margin[@"top"] floatValue],
[(NSNumber *) margin[@"right"] floatValue],
[(NSNumber *) margin[@"bottom"] floatValue]);
}
NSNumber *alignment = params[@"alignment"];
if (alignment) {
self.layoutConfig.alignment = (DoricGravity) [alignment integerValue];
}
NSNumber *weight = params[@"weight"];
if (weight) {
self.layoutConfig.weight = (DoricGravity) [weight integerValue];
}
} }
- (NSDictionary *)transformation { - (NSDictionary *)transformation {

View File

@ -37,6 +37,9 @@ NS_ASSUME_NONNULL_BEGIN
@property(nonatomic) CGFloat left; @property(nonatomic) CGFloat left;
@property(nonatomic) CGFloat right; @property(nonatomic) CGFloat right;
@property(nonatomic) CGFloat bottom; @property(nonatomic) CGFloat bottom;
@property(nonatomic, copy) NSString *tagString;
- (UIView *)viewWithTagString:(NSString *)tagString;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -22,8 +22,25 @@
// //
#import "UIView+Doric.h" #import "UIView+Doric.h"
#import <objc/runtime.h>
static const void *kTagString = &kTagString;
@implementation UIView (Doric) @implementation UIView (Doric)
- (void)setTagString:(NSString *)tagString {
objc_setAssociatedObject(self, kTagString, tagString, OBJC_ASSOCIATION_COPY_NONATOMIC);
self.tag = [tagString hash];
}
- (NSString *)tagString {
return objc_getAssociatedObject(self, kTagString);
}
- (UIView *)viewWithTagString:(NSString *)tagString {
// notice the potential hash collision
return [self viewWithTag:[tagString hash]];
}
- (CGFloat)x { - (CGFloat)x {
return self.frame.origin.x; return self.frame.origin.x;

View File

@ -73,7 +73,7 @@ void ShowToast(NSString *text, DoricGravity gravity) {
label.centerX = superView.width / 2; label.centerX = superView.width / 2;
if ((gravity & DoricGravityBottom) == DoricGravityBottom) { if ((gravity & DoricGravityBottom) == DoricGravityBottom) {
label.bottom = superView.height - 20; label.bottom = superView.height - 20;
} else if ((gravity & DoricGravityTOP) == DoricGravityTOP) { } else if ((gravity & DoricGravityTop) == DoricGravityTop) {
label.top = 108; label.top = 108;
} else { } else {
label.centerY = (superView.height - 88) / 2; label.centerY = (superView.height - 88) / 2;