diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 5d82ade6148d8c..c953a710aa69b5 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -350,7 +350,18 @@ const ScrollView = createReactClass({ * @platform ios */ zoomScale: PropTypes.number, - + /** + * This property specifies how the safe area insets are used to modify the + * content area of the scroll view. The default value of this property is + * "never". Available on iOS 11 and later. + * @platform ios + */ + contentInsetAdjustmentBehavior: PropTypes.oneOf([ + 'automatic', + 'scrollableAxes', + 'never', // default + 'always', + ]), /** * A RefreshControl component, used to provide pull-to-refresh * functionality for the ScrollView. Only works for vertical ScrollViews diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m index 0035da12872d99..b2e7cc3c9fd31f 100644 --- a/React/Views/RCTScrollView.m +++ b/React/Views/RCTScrollView.m @@ -333,9 +333,21 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher if ((self = [super initWithFrame:CGRectZero])) { _eventDispatcher = eventDispatcher; + _scrollView = [[RCTCustomScrollView alloc] initWithFrame:CGRectZero]; _scrollView.delegate = self; _scrollView.delaysContentTouches = NO; + +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ + // `contentInsetAdjustmentBehavior` is only available since iOS 11. + // We set the default behavior to "never" so that iOS + // doesn't do weird things to UIScrollView insets automatically + // and keeps it as an opt-in behavior. + if ([_scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) { + _scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; + } +#endif + _automaticallyAdjustContentInsets = YES; _DEPRECATED_sendUpdatedChildFrames = NO; _contentInset = UIEdgeInsetsZero; @@ -883,6 +895,18 @@ - (type)getter \ RCT_SET_AND_PRESERVE_OFFSET(setZoomScale, zoomScale, CGFloat); RCT_SET_AND_PRESERVE_OFFSET(setScrollIndicatorInsets, scrollIndicatorInsets, UIEdgeInsets); +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ +- (void)setContentInsetAdjustmentBehavior:(UIScrollViewContentInsetAdjustmentBehavior)behavior +{ + // `contentInsetAdjustmentBehavior` is available since iOS 11. + if ([_scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) { + CGPoint contentOffset = _scrollView.contentOffset; + _scrollView.contentInsetAdjustmentBehavior = behavior; + _scrollView.contentOffset = contentOffset; + } +} +#endif + - (void)sendScrollEventWithName:(NSString *)eventName scrollView:(UIScrollView *)scrollView userData:(NSDictionary *)userData diff --git a/React/Views/RCTScrollViewManager.m b/React/Views/RCTScrollViewManager.m index bba98f3b96eee4..a719244f59a8bd 100644 --- a/React/Views/RCTScrollViewManager.m +++ b/React/Views/RCTScrollViewManager.m @@ -36,6 +36,15 @@ @implementation RCTConvert (UIScrollView) @"white": @(UIScrollViewIndicatorStyleWhite), }), UIScrollViewIndicatorStyleDefault, integerValue) +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ +RCT_ENUM_CONVERTER(UIScrollViewContentInsetAdjustmentBehavior, (@{ + @"automatic": @(UIScrollViewContentInsetAdjustmentAutomatic), + @"scrollableAxes": @(UIScrollViewContentInsetAdjustmentScrollableAxes), + @"never": @(UIScrollViewContentInsetAdjustmentNever), + @"always": @(UIScrollViewContentInsetAdjustmentAlways), +}), UIScrollViewContentInsetAdjustmentNever, integerValue) +#endif + @end @implementation RCTScrollViewManager @@ -81,6 +90,9 @@ - (UIView *)view RCT_EXPORT_VIEW_PROPERTY(onMomentumScrollEnd, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onScrollAnimationEnd, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(DEPRECATED_sendUpdatedChildFrames, BOOL) +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ +RCT_EXPORT_VIEW_PROPERTY(contentInsetAdjustmentBehavior, UIScrollViewContentInsetAdjustmentBehavior) +#endif // overflow is used both in css-layout as well as by react-native. In css-layout // we always want to treat overflow as scroll but depending on what the overflow