From 55efff976a124bd0bdfdaf4c25827653d3c97573 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Thu, 25 Aug 2022 14:19:08 +0800 Subject: [PATCH] iOS: Scroller support fit width or height --- doric-iOS/Pod/Classes/Shader/DoricLayouts.h | 16 +++ doric-iOS/Pod/Classes/Shader/DoricLayouts.m | 113 +++++++++++++++--- .../Pod/Classes/Shader/DoricScrollerNode.h | 4 - .../Pod/Classes/Shader/DoricScrollerNode.m | 30 +---- 4 files changed, 114 insertions(+), 49 deletions(-) diff --git a/doric-iOS/Pod/Classes/Shader/DoricLayouts.h b/doric-iOS/Pod/Classes/Shader/DoricLayouts.h index 40bcf604..a376f4b5 100644 --- a/doric-iOS/Pod/Classes/Shader/DoricLayouts.h +++ b/doric-iOS/Pod/Classes/Shader/DoricLayouts.h @@ -26,12 +26,25 @@ typedef UIEdgeInsets DoricPadding; DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom); +typedef NS_ENUM(NSInteger, DoricMeasureSpecMode) { + DoricMeasureUnspecified = 0, + DoricMeasureExactly = 1, + DoricMeasureAtMost = 2, +}; + +struct DoricMeasureSpec { + DoricMeasureSpecMode mode; + CGFloat size; +}; + +typedef struct DoricMeasureSpec DoricMeasureSpec; typedef NS_ENUM(NSInteger, DoricLayoutType) { DoricUndefined = 0, DoricStack = 1, DoricVLayout = 2, DoricHLayout = 3, + DoricScroller = 4, }; typedef NS_ENUM(NSInteger, DoricLayoutSpec) { @@ -121,3 +134,6 @@ typedef NS_ENUM(NSInteger, DoricGravity) { @property(nonatomic, strong) DoricLayout *doricLayout; @end +@interface DoricScrollView : UIScrollView +@property(nonatomic, strong) UIView *contentView; +@end \ No newline at end of file diff --git a/doric-iOS/Pod/Classes/Shader/DoricLayouts.m b/doric-iOS/Pod/Classes/Shader/DoricLayouts.m index d47cded5..c5b4f34e 100644 --- a/doric-iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/doric-iOS/Pod/Classes/Shader/DoricLayouts.m @@ -91,19 +91,6 @@ - (DoricLayout *)doricLayout { @end -typedef NS_ENUM(NSInteger, DoricMeasureSpecMode) { - DoricMeasureUnspecified = 0, - DoricMeasureExactly = 1, - DoricMeasureAtMost = 2, -}; - -struct DoricMeasureSpec { - DoricMeasureSpecMode mode; - CGFloat size; -}; - -typedef struct DoricMeasureSpec DoricMeasureSpec; - struct DoricSizeAndState { NSUInteger state; CGFloat size; @@ -181,7 +168,7 @@ - (DoricMeasureSpec)getRootMeasureSpec:(CGFloat)targetSize return DoricMeasureSpecMake(DoricMeasureExactly, targetSize); case DoricLayoutFit: if ([self.view.superview isKindOfClass:UIScrollView.class]) { - return DoricMeasureSpecMake(DoricMeasureAtMost, CGFLOAT_MAX); + return DoricMeasureSpecMake(DoricMeasureUnspecified, 0); } return DoricMeasureSpecMake(DoricMeasureAtMost, targetSize); default: @@ -481,6 +468,10 @@ - (void)measureWidth:(DoricMeasureSpec)widthSpec height:(DoricMeasureSpec)height [self horizontalMeasureWidth:widthSpec height:heightSpec]; break; } + case DoricScroller: { + [self scrollerMeasureWidth:widthSpec height:heightSpec]; + break; + } default: { [self undefinedMeasureWidth:widthSpec height:heightSpec]; break; @@ -1037,11 +1028,71 @@ - (void)stackMeasureWidth:(DoricMeasureSpec)widthMeasureSpec } } +- (void)scrollerMeasureWidth:(DoricMeasureSpec)widthMeasureSpec + height:(DoricMeasureSpec)heightMeasureSpec { + DoricScrollView *scrollView = (DoricScrollView *) self.view; + DoricLayout *childLayout = scrollView.contentView.doricLayout; + + [self measureChild:childLayout + widthSpec:widthMeasureSpec usedWidth:0 + heightSpec:heightMeasureSpec usedHeight:0]; + + CGFloat maxWidth, maxHeight; + + maxWidth = childLayout.measuredWidth + + childLayout.marginLeft + childLayout.marginRight; + maxHeight = childLayout.measuredHeight + + childLayout.marginTop + childLayout.marginBottom; + + maxWidth += self.paddingLeft + self.paddingRight; + maxHeight += self.paddingTop + self.paddingBottom; + + maxWidth = MAX(maxWidth, self.minWidth); + maxHeight = MAX(maxHeight, self.minHeight); + + DoricSizeAndState widthSizeAndState = [self resolveSizeAndState:maxWidth + spec:widthMeasureSpec + childMeasuredState:0]; + DoricSizeAndState heightSizeAndState = [self resolveSizeAndState:maxHeight + spec:heightMeasureSpec + childMeasuredState:0]; + self.measuredWidth = widthSizeAndState.size; + self.measuredHeight = heightSizeAndState.size; + + if (widthMeasureSpec.mode == DoricMeasureUnspecified + && heightMeasureSpec.mode == DoricMeasureUnspecified) { + return; + } + + CGFloat width = self.measuredWidth - self.paddingLeft - self.paddingRight; + CGFloat height = self.measuredHeight - self.paddingTop - self.paddingBottom; + DoricMeasureSpec childWidthMeasureSpec, childHeightMeasureSpec; + if (childLayout.widthSpec == DoricLayoutMost) { + childWidthMeasureSpec = DoricMeasureSpecMake(DoricMeasureExactly, width); + } else { + widthMeasureSpec = DoricMeasureSpecMake(DoricMeasureUnspecified, 0); + childWidthMeasureSpec = [self getChildMeasureSpec:widthMeasureSpec + padding:self.paddingLeft + self.paddingRight + childLayoutSpec:childLayout.widthSpec + childSize:childLayout.width]; + } + + if (childLayout.heightSpec == DoricLayoutMost) { + childHeightMeasureSpec = DoricMeasureSpecMake(DoricMeasureExactly, height); + } else { + heightMeasureSpec = DoricMeasureSpecMake(DoricMeasureUnspecified, 0); + childHeightMeasureSpec = [self getChildMeasureSpec:heightMeasureSpec + padding:self.paddingTop + self.paddingBottom + childLayoutSpec:childLayout.heightSpec + childSize:childLayout.height]; + } + [childLayout measureWidth:childWidthMeasureSpec height:childHeightMeasureSpec]; +} + - (void)undefinedMeasureWidth:(DoricMeasureSpec)widthMeasureSpec height:(DoricMeasureSpec)heightMeasureSpec { CGSize targetSize = CGSizeMake(widthMeasureSpec.size - self.paddingLeft - self.paddingRight, heightMeasureSpec.size - self.paddingTop - self.paddingBottom); - //TODO should check this CGSize measuredSize = [self.view sizeThatFits:targetSize]; CGFloat contentWidth = measuredSize.width; @@ -1107,6 +1158,10 @@ - (void)layout { [self layoutHLayout]; break; } + case DoricScroller: { + [self layoutScroller]; + break; + } default: { break; } @@ -1116,7 +1171,9 @@ - (void)layout { #pragma setFrame - (void)setFrame { - if (self.layoutType != DoricUndefined) { + if (self.layoutType == DoricScroller) { + [((DoricScrollView *) self.view).contentView.doricLayout setFrame]; + } else if (self.layoutType != DoricUndefined) { [self.view.subviews forEach:^(__kindof UIView *obj) { [obj.doricLayout setFrame]; }]; @@ -1320,5 +1377,29 @@ - (void)layoutHLayout { } } +- (void)layoutScroller { + DoricScrollView *scrollView = (DoricScrollView *) self.view; + DoricLayout *layout = scrollView.contentView.doricLayout; + if (layout.disabled) { + return; + } + [layout layout]; +} @end + +@implementation DoricScrollView + +- (void)setContentView:(UIView *)contentView { + if (_contentView) { + [_contentView removeFromSuperview]; + } + _contentView = contentView; + [self addSubview:contentView]; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + self.contentSize = self.contentView.frame.size; +} +@end \ No newline at end of file diff --git a/doric-iOS/Pod/Classes/Shader/DoricScrollerNode.h b/doric-iOS/Pod/Classes/Shader/DoricScrollerNode.h index 53c1349d..241dea1b 100644 --- a/doric-iOS/Pod/Classes/Shader/DoricScrollerNode.h +++ b/doric-iOS/Pod/Classes/Shader/DoricScrollerNode.h @@ -23,9 +23,5 @@ #import "DoricSuperNode.h" #import "DoricScrollableProtocol.h" -@interface DoricScrollView : UIScrollView -@property(nonatomic, strong) UIView *contentView; -@end - @interface DoricScrollerNode : DoricSuperNode @end \ No newline at end of file diff --git a/doric-iOS/Pod/Classes/Shader/DoricScrollerNode.m b/doric-iOS/Pod/Classes/Shader/DoricScrollerNode.m index 4dd315b9..69b6bf2e 100644 --- a/doric-iOS/Pod/Classes/Shader/DoricScrollerNode.m +++ b/doric-iOS/Pod/Classes/Shader/DoricScrollerNode.m @@ -25,34 +25,6 @@ #import "DoricPromise.h" #import "DoricJSDispatcher.h" -@implementation DoricScrollView - -- (void)setContentView:(UIView *)contentView { - if (_contentView) { - [_contentView removeFromSuperview]; - } - _contentView = contentView; - [self addSubview:contentView]; -} - -- (CGSize)sizeThatFits:(CGSize)size { - if (self.contentView) { - if (!self.contentView.doricLayout.resolved) { - [self.contentView.doricLayout apply:size]; - } - return CGSizeMake( - self.contentView.doricLayout.measuredWidth, - self.contentView.doricLayout.measuredHeight); - } - return CGSizeZero; -} - -- (void)layoutSubviews { - [super layoutSubviews]; - self.contentSize = self.contentView.frame.size; -} -@end - @interface DoricScrollerNode () @property(nonatomic, strong) DoricViewNode *childNode; @property(nonatomic, copy) NSString *childViewId; @@ -71,6 +43,7 @@ - (DoricScrollView *)build { if (@available(iOS 11, *)) { it.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } + it.doricLayout.layoutType = DoricScroller; }]; } @@ -123,7 +96,6 @@ - (void)afterBlended:(NSDictionary *)props { - (void)requestLayout { [self.childNode requestLayout]; - [self.view.contentView.doricLayout apply:self.view.frame.size]; [super requestLayout]; }