Skip to content

Commit

Permalink
Add 'contentInsetAdjustmentBehavior' (new in iOS 11) to ScrollView
Browse files Browse the repository at this point in the history
Summary:
In iOS11, Apple added a new layout feature called "Safe Areas" (this blog post talks a bit about it: https://www.bignerdranch.com/blog/wwdc-2017-large-titles-and-safe-area-layout-guides/).

UIScrollView is one component that is affected by this change in Apple's API. When the `contentInsetAdjustmentBehavior` is set to `automatic`, for example, it will adjust the insets (and override any manually set insets) automatically based on whether or not there's a UINavigationBar, a UITabBar, a visible status bar, etc on the screen. Frustratingly, Apple decided to default to `Automatic` for this behavior, which will cause any apps that set contentInset/contentContainerStyle padding to have their values offset by, at the very least, the size of the status bar, when they compile their app for iOS 11. Here's more information about this behavior: https://developer.apple.com/documentation/uikit/uiscrollview/2902261-contentinsetadjustmentbehavior?language=objc

Mostly, this is a really straightforward change -- it simply adds a new iOS-only prop to ScrollView that allows setting `contentInsetAdjustmentBehavior`. But I did decide to default the behavior to `never`, so that it mimics the behavior we've seen in iOS < 11. I think it's good to keep something as crucial as scrollview content insets non-magical, and also keep it behaving similarly between platforms.
Closes facebook#15023

Reviewed By: javache

Differential Revision: D5517552

Pulled By: hramos

fbshipit-source-id: c9ce4bf331b3d243228268d826fdd4dcee99981d
  • Loading branch information
Adam Miskiewicz authored and ide committed Aug 4, 2017
1 parent bcc3f77 commit caf924d
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 1 deletion.
13 changes: 12 additions & 1 deletion Libraries/Components/ScrollView/ScrollView.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions React/Views/RCTScrollView.m
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions React/Views/RCTScrollViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit caf924d

Please sign in to comment.