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);
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

View File

@ -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

View File

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

View File

@ -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 () <UIScrollViewDelegate>
@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];
}