iOS: Scroller support fit width or height

This commit is contained in:
pengfei.zhou 2022-08-25 14:19:08 +08:00 committed by osborn
parent 0c868f095d
commit 55efff976a
4 changed files with 114 additions and 49 deletions

View File

@ -26,12 +26,25 @@ 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, DoricMeasureSpecMode) {
DoricMeasureUnspecified = 0,
DoricMeasureExactly = 1,
DoricMeasureAtMost = 2,
};
struct DoricMeasureSpec {
DoricMeasureSpecMode mode;
CGFloat size;
};
typedef struct DoricMeasureSpec DoricMeasureSpec;
typedef NS_ENUM(NSInteger, DoricLayoutType) { typedef NS_ENUM(NSInteger, DoricLayoutType) {
DoricUndefined = 0, DoricUndefined = 0,
DoricStack = 1, DoricStack = 1,
DoricVLayout = 2, DoricVLayout = 2,
DoricHLayout = 3, DoricHLayout = 3,
DoricScroller = 4,
}; };
typedef NS_ENUM(NSInteger, DoricLayoutSpec) { typedef NS_ENUM(NSInteger, DoricLayoutSpec) {
@ -121,3 +134,6 @@ typedef NS_ENUM(NSInteger, DoricGravity) {
@property(nonatomic, strong) DoricLayout *doricLayout; @property(nonatomic, strong) DoricLayout *doricLayout;
@end @end
@interface DoricScrollView : UIScrollView
@property(nonatomic, strong) UIView *contentView;
@end

View File

@ -91,19 +91,6 @@ - (DoricLayout *)doricLayout {
@end @end
typedef NS_ENUM(NSInteger, DoricMeasureSpecMode) {
DoricMeasureUnspecified = 0,
DoricMeasureExactly = 1,
DoricMeasureAtMost = 2,
};
struct DoricMeasureSpec {
DoricMeasureSpecMode mode;
CGFloat size;
};
typedef struct DoricMeasureSpec DoricMeasureSpec;
struct DoricSizeAndState { struct DoricSizeAndState {
NSUInteger state; NSUInteger state;
CGFloat size; CGFloat size;
@ -181,7 +168,7 @@ - (DoricMeasureSpec)getRootMeasureSpec:(CGFloat)targetSize
return DoricMeasureSpecMake(DoricMeasureExactly, targetSize); return DoricMeasureSpecMake(DoricMeasureExactly, targetSize);
case DoricLayoutFit: case DoricLayoutFit:
if ([self.view.superview isKindOfClass:UIScrollView.class]) { if ([self.view.superview isKindOfClass:UIScrollView.class]) {
return DoricMeasureSpecMake(DoricMeasureAtMost, CGFLOAT_MAX); return DoricMeasureSpecMake(DoricMeasureUnspecified, 0);
} }
return DoricMeasureSpecMake(DoricMeasureAtMost, targetSize); return DoricMeasureSpecMake(DoricMeasureAtMost, targetSize);
default: default:
@ -481,6 +468,10 @@ - (void)measureWidth:(DoricMeasureSpec)widthSpec height:(DoricMeasureSpec)height
[self horizontalMeasureWidth:widthSpec height:heightSpec]; [self horizontalMeasureWidth:widthSpec height:heightSpec];
break; break;
} }
case DoricScroller: {
[self scrollerMeasureWidth:widthSpec height:heightSpec];
break;
}
default: { default: {
[self undefinedMeasureWidth:widthSpec height:heightSpec]; [self undefinedMeasureWidth:widthSpec height:heightSpec];
break; 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 - (void)undefinedMeasureWidth:(DoricMeasureSpec)widthMeasureSpec
height:(DoricMeasureSpec)heightMeasureSpec { height:(DoricMeasureSpec)heightMeasureSpec {
CGSize targetSize = CGSizeMake(widthMeasureSpec.size - self.paddingLeft - self.paddingRight, CGSize targetSize = CGSizeMake(widthMeasureSpec.size - self.paddingLeft - self.paddingRight,
heightMeasureSpec.size - self.paddingTop - self.paddingBottom); heightMeasureSpec.size - self.paddingTop - self.paddingBottom);
//TODO should check this
CGSize measuredSize = [self.view sizeThatFits:targetSize]; CGSize measuredSize = [self.view sizeThatFits:targetSize];
CGFloat contentWidth = measuredSize.width; CGFloat contentWidth = measuredSize.width;
@ -1107,6 +1158,10 @@ - (void)layout {
[self layoutHLayout]; [self layoutHLayout];
break; break;
} }
case DoricScroller: {
[self layoutScroller];
break;
}
default: { default: {
break; break;
} }
@ -1116,7 +1171,9 @@ - (void)layout {
#pragma setFrame #pragma setFrame
- (void)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) { [self.view.subviews forEach:^(__kindof UIView *obj) {
[obj.doricLayout setFrame]; [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 @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

View File

@ -23,9 +23,5 @@
#import "DoricSuperNode.h" #import "DoricSuperNode.h"
#import "DoricScrollableProtocol.h" #import "DoricScrollableProtocol.h"
@interface DoricScrollView : UIScrollView
@property(nonatomic, strong) UIView *contentView;
@end
@interface DoricScrollerNode : DoricSuperNode<DoricScrollView *> <DoricScrollableProtocol> @interface DoricScrollerNode : DoricSuperNode<DoricScrollView *> <DoricScrollableProtocol>
@end @end

View File

@ -25,34 +25,6 @@
#import "DoricPromise.h" #import "DoricPromise.h"
#import "DoricJSDispatcher.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 () <UIScrollViewDelegate> @interface DoricScrollerNode () <UIScrollViewDelegate>
@property(nonatomic, strong) DoricViewNode *childNode; @property(nonatomic, strong) DoricViewNode *childNode;
@property(nonatomic, copy) NSString *childViewId; @property(nonatomic, copy) NSString *childViewId;
@ -71,6 +43,7 @@ - (DoricScrollView *)build {
if (@available(iOS 11, *)) { if (@available(iOS 11, *)) {
it.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; it.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} }
it.doricLayout.layoutType = DoricScroller;
}]; }];
} }
@ -123,7 +96,6 @@ - (void)afterBlended:(NSDictionary *)props {
- (void)requestLayout { - (void)requestLayout {
[self.childNode requestLayout]; [self.childNode requestLayout];
[self.view.contentView.doricLayout apply:self.view.frame.size];
[super requestLayout]; [super requestLayout];
} }