From 64db98febfd72f7c02b8e0aedc2f605ed4f47f14 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 17 May 2019 19:59:10 -0700 Subject: [PATCH] Fabric: Improvements in RCTScrollViewComponentView Summary: This diff contains two changes: * The actual UIScrollView is now mounted inside the component as `contentView` which mostly means that border-props will properly affect the layout of the scroll view (the scroll view will be laid out inside borders, not on top of those). And that also simplifies the code. * Now the component view exposes the actual scroll view, its delegate splitter, and the container view defining a single interface for all possible integration that can be done with the Scroll View Component. Reviewed By: mdvacca Differential Revision: D15397283 fbshipit-source-id: 35e860b8bf55fbd4d0a5f4116f79e4507df79098 --- .../ScrollView/RCTScrollViewComponentView.h | 25 ++++++++++++++++++- .../ScrollView/RCTScrollViewComponentView.mm | 21 +++++++--------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.h b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.h index 5840a9d3d36fe4..373f2635e36cb8 100644 --- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.h +++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.h @@ -8,14 +8,37 @@ #import #import +#import NS_ASSUME_NONNULL_BEGIN -/** +/* * UIView class for component. + * + * By design, the class does not implement any logic that contradicts to the normal behavior of UIScrollView and does + * not contain any special/custom support for things like floating headers, pull-to-refresh components, + * keyboard-avoiding functionality and so on. All that complexity must be implemented inside those components in order + * to keep the complexity of this component manageable. */ @interface RCTScrollViewComponentView : RCTViewComponentView +/* + * Returns an actual UIScrollView that this component uses under the hood. + */ +@property (nonatomic, strong, readonly) UIScrollView *scrollView; + +/* + * Returns the subview of the scroll view that the component uses to mount all subcomponents into. That's useful to + * separate component views from auxiliary views to be able to reliably implement pull-to-refresh- and RTL-related + * functionality. + */ +@property (nonatomic, strong, readonly) UIView *containerView; + +/* + * Returns a delegate splitter that can be used to subscribe for UIScrollView delegate. + */ +@property (nonatomic, strong, readonly) RNGenericDelegateSplitter> *scrollViewDelegateSplitter; + @end NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm index 3ac1526ad151e5..c72eb87122d3a7 100644 --- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm @@ -8,7 +8,6 @@ #import "RCTScrollViewComponentView.h" #import -#import #import #import @@ -28,11 +27,8 @@ @interface RCTScrollViewComponentView () @end @implementation RCTScrollViewComponentView { - RCTEnhancedScrollView *_Nonnull _scrollView; - UIView *_Nonnull _contentView; ScrollViewShadowNode::ConcreteState::Shared _state; CGSize _contentSize; - RNGenericDelegateSplitter> *_scrollViewDelegateSplitter; } - (instancetype)initWithFrame:(CGRect)frame @@ -42,11 +38,11 @@ - (instancetype)initWithFrame:(CGRect)frame _props = defaultProps; _scrollView = [[RCTEnhancedScrollView alloc] initWithFrame:self.bounds]; - _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _scrollView.delaysContentTouches = NO; - _contentView = [[UIView alloc] initWithFrame:_scrollView.bounds]; - [_scrollView addSubview:_contentView]; - [self addSubview:_scrollView]; + self.contentView = _scrollView; + + _containerView = [[UIView alloc] initWithFrame:CGRectZero]; + [_scrollView addSubview:_containerView]; _scrollViewDelegateSplitter = [[RNGenericDelegateSplitter alloc] initWithDelegateUpdateBlock:^(id delegate) { self->_scrollView.delegate = delegate; @@ -79,7 +75,8 @@ - (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps #define REMAP_VIEW_PROP(reactName, localName) REMAP_PROP(reactName, localName, self) #define MAP_VIEW_PROP(name) REMAP_VIEW_PROP(name, name) -#define REMAP_SCROLL_VIEW_PROP(reactName, localName) REMAP_PROP(reactName, localName, _scrollView) +#define REMAP_SCROLL_VIEW_PROP(reactName, localName) \ + REMAP_PROP(reactName, localName, ((RCTEnhancedScrollView *)_scrollView)) #define MAP_SCROLL_VIEW_PROP(name) REMAP_SCROLL_VIEW_PROP(name, name) // FIXME: Commented props are not supported yet. @@ -122,18 +119,18 @@ - (void)updateState:(State::Shared)state oldState:(State::Shared)oldState } _contentSize = contentSize; - _contentView.frame = CGRect{CGPointZero, contentSize}; + _containerView.frame = CGRect{CGPointZero, contentSize}; _scrollView.contentSize = contentSize; } - (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index { - [_contentView insertSubview:childComponentView atIndex:index]; + [_containerView insertSubview:childComponentView atIndex:index]; } - (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index { - RCTAssert(childComponentView.superview == _contentView, @"Attempt to unmount improperly mounted component view."); + RCTAssert(childComponentView.superview == _containerView, @"Attempt to unmount improperly mounted component view."); [childComponentView removeFromSuperview]; }