2017-09-24 22:57:31 -07:00
|
|
|
/**
|
2018-09-11 15:27:47 -07:00
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
2017-09-24 22:57:31 -07:00
|
|
|
*
|
2018-02-16 18:24:55 -08:00
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
2017-09-24 22:57:31 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
#import "RCTSafeAreaView.h"
|
|
|
|
|
|
|
|
#import <React/RCTBridge.h>
|
|
|
|
#import <React/RCTUIManager.h>
|
|
|
|
|
|
|
|
#import "RCTSafeAreaViewLocalData.h"
|
|
|
|
|
|
|
|
@implementation RCTSafeAreaView {
|
2017-11-02 08:44:10 -07:00
|
|
|
__weak RCTBridge *_bridge;
|
2017-09-24 22:57:31 -07:00
|
|
|
UIEdgeInsets _currentSafeAreaInsets;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
|
|
|
{
|
|
|
|
if (self = [super initWithFrame:CGRectZero]) {
|
|
|
|
_bridge = bridge;
|
2018-09-11 21:14:44 -07:00
|
|
|
_emulateUnlessSupported = YES; // The default.
|
2017-09-24 22:57:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)decoder)
|
|
|
|
RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
|
|
|
|
|
2018-09-11 21:14:44 -07:00
|
|
|
- (BOOL)isSupportedByOS
|
|
|
|
{
|
|
|
|
return [self respondsToSelector:@selector(safeAreaInsets)];
|
2017-09-24 22:57:31 -07:00
|
|
|
}
|
|
|
|
|
2018-09-11 21:14:44 -07:00
|
|
|
- (UIEdgeInsets)safeAreaInsetsIfSupportedAndEnabled
|
2017-09-24 22:57:31 -07:00
|
|
|
{
|
2018-09-11 21:14:44 -07:00
|
|
|
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
|
|
|
|
if (self.isSupportedByOS) {
|
|
|
|
return self.safeAreaInsets;
|
2017-09-24 22:57:31 -07:00
|
|
|
}
|
Make SafeAreaView to work on iOS < 11 (#18534)
Summary:
Currently `SafeAreaView` works only on iOS 11, because implemented in terms of native safeArea API, that not exists in older iOS versions. But this make it hard to use the component in real applications, because content will be under top bars on older versions of iOS and no reliable way to workaround this in js. More motivation in #17638
This changeset emulate safe area in terms of `UIViewController` layout guides API if safeArea not available.
Fixes #17638, #18255
I run RNTester with these simulators: iPhone6 (9.3), iPhone6 (10.0), iPhone6 (11.2), iPhoneX (11.2)
- Start RNTester application
- Look on top header, it should not overlap status bar
- Go to the `<SafeAreaView>` example, open modal
- Modal area should not overlap status bar
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_20662C5B.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_20662CC8.png" width="40%">
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_pr_20662DE6.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_pr_20662DA8.png" width="40%">
[IOS] [BUGFIX] [SafeAreaView] - Make SafeAreaView to work on iOS < 11
Pull Request resolved: https://github.com/facebook/react-native/pull/18534
Reviewed By: PeteTheHeat, shergin
Differential Revision: D9166052
Pulled By: hramos
fbshipit-source-id: c086e1ae4af13110a7453b770ca75b6e0d5321ea
2018-08-23 11:58:55 -07:00
|
|
|
#endif
|
2018-09-11 21:14:44 -07:00
|
|
|
return self.emulateUnlessSupported ? self.emulatedSafeAreaInsets : UIEdgeInsetsZero;
|
|
|
|
}
|
Make SafeAreaView to work on iOS < 11 (#18534)
Summary:
Currently `SafeAreaView` works only on iOS 11, because implemented in terms of native safeArea API, that not exists in older iOS versions. But this make it hard to use the component in real applications, because content will be under top bars on older versions of iOS and no reliable way to workaround this in js. More motivation in #17638
This changeset emulate safe area in terms of `UIViewController` layout guides API if safeArea not available.
Fixes #17638, #18255
I run RNTester with these simulators: iPhone6 (9.3), iPhone6 (10.0), iPhone6 (11.2), iPhoneX (11.2)
- Start RNTester application
- Look on top header, it should not overlap status bar
- Go to the `<SafeAreaView>` example, open modal
- Modal area should not overlap status bar
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_20662C5B.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_20662CC8.png" width="40%">
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_pr_20662DE6.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_pr_20662DA8.png" width="40%">
[IOS] [BUGFIX] [SafeAreaView] - Make SafeAreaView to work on iOS < 11
Pull Request resolved: https://github.com/facebook/react-native/pull/18534
Reviewed By: PeteTheHeat, shergin
Differential Revision: D9166052
Pulled By: hramos
fbshipit-source-id: c086e1ae4af13110a7453b770ca75b6e0d5321ea
2018-08-23 11:58:55 -07:00
|
|
|
|
2018-09-11 21:14:44 -07:00
|
|
|
- (UIEdgeInsets)emulatedSafeAreaInsets
|
Make SafeAreaView to work on iOS < 11 (#18534)
Summary:
Currently `SafeAreaView` works only on iOS 11, because implemented in terms of native safeArea API, that not exists in older iOS versions. But this make it hard to use the component in real applications, because content will be under top bars on older versions of iOS and no reliable way to workaround this in js. More motivation in #17638
This changeset emulate safe area in terms of `UIViewController` layout guides API if safeArea not available.
Fixes #17638, #18255
I run RNTester with these simulators: iPhone6 (9.3), iPhone6 (10.0), iPhone6 (11.2), iPhoneX (11.2)
- Start RNTester application
- Look on top header, it should not overlap status bar
- Go to the `<SafeAreaView>` example, open modal
- Modal area should not overlap status bar
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_20662C5B.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_20662CC8.png" width="40%">
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_pr_20662DE6.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_pr_20662DA8.png" width="40%">
[IOS] [BUGFIX] [SafeAreaView] - Make SafeAreaView to work on iOS < 11
Pull Request resolved: https://github.com/facebook/react-native/pull/18534
Reviewed By: PeteTheHeat, shergin
Differential Revision: D9166052
Pulled By: hramos
fbshipit-source-id: c086e1ae4af13110a7453b770ca75b6e0d5321ea
2018-08-23 11:58:55 -07:00
|
|
|
{
|
|
|
|
UIViewController* vc = self.reactViewController;
|
2018-09-11 21:14:44 -07:00
|
|
|
|
Make SafeAreaView to work on iOS < 11 (#18534)
Summary:
Currently `SafeAreaView` works only on iOS 11, because implemented in terms of native safeArea API, that not exists in older iOS versions. But this make it hard to use the component in real applications, because content will be under top bars on older versions of iOS and no reliable way to workaround this in js. More motivation in #17638
This changeset emulate safe area in terms of `UIViewController` layout guides API if safeArea not available.
Fixes #17638, #18255
I run RNTester with these simulators: iPhone6 (9.3), iPhone6 (10.0), iPhone6 (11.2), iPhoneX (11.2)
- Start RNTester application
- Look on top header, it should not overlap status bar
- Go to the `<SafeAreaView>` example, open modal
- Modal area should not overlap status bar
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_20662C5B.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_20662CC8.png" width="40%">
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_pr_20662DE6.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_pr_20662DA8.png" width="40%">
[IOS] [BUGFIX] [SafeAreaView] - Make SafeAreaView to work on iOS < 11
Pull Request resolved: https://github.com/facebook/react-native/pull/18534
Reviewed By: PeteTheHeat, shergin
Differential Revision: D9166052
Pulled By: hramos
fbshipit-source-id: c086e1ae4af13110a7453b770ca75b6e0d5321ea
2018-08-23 11:58:55 -07:00
|
|
|
if (!vc) {
|
2018-09-11 21:14:44 -07:00
|
|
|
return UIEdgeInsetsZero;
|
Make SafeAreaView to work on iOS < 11 (#18534)
Summary:
Currently `SafeAreaView` works only on iOS 11, because implemented in terms of native safeArea API, that not exists in older iOS versions. But this make it hard to use the component in real applications, because content will be under top bars on older versions of iOS and no reliable way to workaround this in js. More motivation in #17638
This changeset emulate safe area in terms of `UIViewController` layout guides API if safeArea not available.
Fixes #17638, #18255
I run RNTester with these simulators: iPhone6 (9.3), iPhone6 (10.0), iPhone6 (11.2), iPhoneX (11.2)
- Start RNTester application
- Look on top header, it should not overlap status bar
- Go to the `<SafeAreaView>` example, open modal
- Modal area should not overlap status bar
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_20662C5B.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_20662CC8.png" width="40%">
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_pr_20662DE6.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_pr_20662DA8.png" width="40%">
[IOS] [BUGFIX] [SafeAreaView] - Make SafeAreaView to work on iOS < 11
Pull Request resolved: https://github.com/facebook/react-native/pull/18534
Reviewed By: PeteTheHeat, shergin
Differential Revision: D9166052
Pulled By: hramos
fbshipit-source-id: c086e1ae4af13110a7453b770ca75b6e0d5321ea
2018-08-23 11:58:55 -07:00
|
|
|
}
|
2018-09-11 21:14:44 -07:00
|
|
|
|
Make SafeAreaView to work on iOS < 11 (#18534)
Summary:
Currently `SafeAreaView` works only on iOS 11, because implemented in terms of native safeArea API, that not exists in older iOS versions. But this make it hard to use the component in real applications, because content will be under top bars on older versions of iOS and no reliable way to workaround this in js. More motivation in #17638
This changeset emulate safe area in terms of `UIViewController` layout guides API if safeArea not available.
Fixes #17638, #18255
I run RNTester with these simulators: iPhone6 (9.3), iPhone6 (10.0), iPhone6 (11.2), iPhoneX (11.2)
- Start RNTester application
- Look on top header, it should not overlap status bar
- Go to the `<SafeAreaView>` example, open modal
- Modal area should not overlap status bar
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_20662C5B.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_20662CC8.png" width="40%">
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_pr_20662DE6.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_pr_20662DA8.png" width="40%">
[IOS] [BUGFIX] [SafeAreaView] - Make SafeAreaView to work on iOS < 11
Pull Request resolved: https://github.com/facebook/react-native/pull/18534
Reviewed By: PeteTheHeat, shergin
Differential Revision: D9166052
Pulled By: hramos
fbshipit-source-id: c086e1ae4af13110a7453b770ca75b6e0d5321ea
2018-08-23 11:58:55 -07:00
|
|
|
CGFloat topLayoutOffset = vc.topLayoutGuide.length;
|
|
|
|
CGFloat bottomLayoutOffset = vc.bottomLayoutGuide.length;
|
|
|
|
CGRect safeArea = vc.view.bounds;
|
|
|
|
safeArea.origin.y += topLayoutOffset;
|
|
|
|
safeArea.size.height -= topLayoutOffset + bottomLayoutOffset;
|
|
|
|
CGRect localSafeArea = [vc.view convertRect:safeArea toView:self];
|
|
|
|
UIEdgeInsets safeAreaInsets = UIEdgeInsetsMake(0, 0, 0, 0);
|
|
|
|
if (CGRectGetMinY(localSafeArea) > CGRectGetMinY(self.bounds)) {
|
|
|
|
safeAreaInsets.top = CGRectGetMinY(localSafeArea) - CGRectGetMinY(self.bounds);
|
|
|
|
}
|
|
|
|
if (CGRectGetMaxY(localSafeArea) < CGRectGetMaxY(self.bounds)) {
|
|
|
|
safeAreaInsets.bottom = CGRectGetMaxY(self.bounds) - CGRectGetMaxY(localSafeArea);
|
|
|
|
}
|
|
|
|
|
2018-09-11 21:14:44 -07:00
|
|
|
return safeAreaInsets;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIEdgeInsets insets2, CGFloat threshold) {
|
|
|
|
return
|
|
|
|
ABS(insets1.left - insets2.left) <= threshold &&
|
|
|
|
ABS(insets1.right - insets2.right) <= threshold &&
|
|
|
|
ABS(insets1.top - insets2.top) <= threshold &&
|
|
|
|
ABS(insets1.bottom - insets2.bottom) <= threshold;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)safeAreaInsetsDidChange
|
|
|
|
{
|
|
|
|
[self invalidateSafeAreaInsets];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)invalidateSafeAreaInsets
|
|
|
|
{
|
|
|
|
[self setSafeAreaInsets:self.safeAreaInsetsIfSupportedAndEnabled];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)layoutSubviews
|
|
|
|
{
|
|
|
|
[super layoutSubviews];
|
|
|
|
|
|
|
|
if (!self.isSupportedByOS && self.emulateUnlessSupported) {
|
|
|
|
[self invalidateSafeAreaInsets];
|
|
|
|
}
|
Make SafeAreaView to work on iOS < 11 (#18534)
Summary:
Currently `SafeAreaView` works only on iOS 11, because implemented in terms of native safeArea API, that not exists in older iOS versions. But this make it hard to use the component in real applications, because content will be under top bars on older versions of iOS and no reliable way to workaround this in js. More motivation in #17638
This changeset emulate safe area in terms of `UIViewController` layout guides API if safeArea not available.
Fixes #17638, #18255
I run RNTester with these simulators: iPhone6 (9.3), iPhone6 (10.0), iPhone6 (11.2), iPhoneX (11.2)
- Start RNTester application
- Look on top header, it should not overlap status bar
- Go to the `<SafeAreaView>` example, open modal
- Modal area should not overlap status bar
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_20662C5B.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_20662CC8.png" width="40%">
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_pr_20662DE6.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_pr_20662DA8.png" width="40%">
[IOS] [BUGFIX] [SafeAreaView] - Make SafeAreaView to work on iOS < 11
Pull Request resolved: https://github.com/facebook/react-native/pull/18534
Reviewed By: PeteTheHeat, shergin
Differential Revision: D9166052
Pulled By: hramos
fbshipit-source-id: c086e1ae4af13110a7453b770ca75b6e0d5321ea
2018-08-23 11:58:55 -07:00
|
|
|
}
|
2017-09-24 22:57:31 -07:00
|
|
|
|
Make SafeAreaView to work on iOS < 11 (#18534)
Summary:
Currently `SafeAreaView` works only on iOS 11, because implemented in terms of native safeArea API, that not exists in older iOS versions. But this make it hard to use the component in real applications, because content will be under top bars on older versions of iOS and no reliable way to workaround this in js. More motivation in #17638
This changeset emulate safe area in terms of `UIViewController` layout guides API if safeArea not available.
Fixes #17638, #18255
I run RNTester with these simulators: iPhone6 (9.3), iPhone6 (10.0), iPhone6 (11.2), iPhoneX (11.2)
- Start RNTester application
- Look on top header, it should not overlap status bar
- Go to the `<SafeAreaView>` example, open modal
- Modal area should not overlap status bar
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_20662C5B.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_20662CC8.png" width="40%">
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_pr_20662DE6.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_pr_20662DA8.png" width="40%">
[IOS] [BUGFIX] [SafeAreaView] - Make SafeAreaView to work on iOS < 11
Pull Request resolved: https://github.com/facebook/react-native/pull/18534
Reviewed By: PeteTheHeat, shergin
Differential Revision: D9166052
Pulled By: hramos
fbshipit-source-id: c086e1ae4af13110a7453b770ca75b6e0d5321ea
2018-08-23 11:58:55 -07:00
|
|
|
- (void)setSafeAreaInsets:(UIEdgeInsets)safeAreaInsets
|
|
|
|
{
|
2017-09-24 22:57:31 -07:00
|
|
|
if (UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_currentSafeAreaInsets = safeAreaInsets;
|
|
|
|
|
Make SafeAreaView to work on iOS < 11 (#18534)
Summary:
Currently `SafeAreaView` works only on iOS 11, because implemented in terms of native safeArea API, that not exists in older iOS versions. But this make it hard to use the component in real applications, because content will be under top bars on older versions of iOS and no reliable way to workaround this in js. More motivation in #17638
This changeset emulate safe area in terms of `UIViewController` layout guides API if safeArea not available.
Fixes #17638, #18255
I run RNTester with these simulators: iPhone6 (9.3), iPhone6 (10.0), iPhone6 (11.2), iPhoneX (11.2)
- Start RNTester application
- Look on top header, it should not overlap status bar
- Go to the `<SafeAreaView>` example, open modal
- Modal area should not overlap status bar
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_20662C5B.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_20662CC8.png" width="40%">
<img src="http://vovkasm.skitch.vovkasm.org/iPhone6_10_pr_20662DE6.png" width="40%"> <img src="http://vovkasm.skitch.vovkasm.org/iPhone6_11_pr_20662DA8.png" width="40%">
[IOS] [BUGFIX] [SafeAreaView] - Make SafeAreaView to work on iOS < 11
Pull Request resolved: https://github.com/facebook/react-native/pull/18534
Reviewed By: PeteTheHeat, shergin
Differential Revision: D9166052
Pulled By: hramos
fbshipit-source-id: c086e1ae4af13110a7453b770ca75b6e0d5321ea
2018-08-23 11:58:55 -07:00
|
|
|
RCTSafeAreaViewLocalData *localData = [[RCTSafeAreaViewLocalData alloc] initWithInsets:safeAreaInsets];
|
2017-09-24 22:57:31 -07:00
|
|
|
[_bridge.uiManager setLocalData:localData forView:self];
|
|
|
|
}
|
|
|
|
|
2018-09-11 21:14:44 -07:00
|
|
|
- (void)setEmulateUnlessSupported:(BOOL)emulateUnlessSupported
|
|
|
|
{
|
|
|
|
if (_emulateUnlessSupported == emulateUnlessSupported) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_emulateUnlessSupported = emulateUnlessSupported;
|
|
|
|
|
|
|
|
[self invalidateSafeAreaInsets];
|
|
|
|
}
|
|
|
|
|
2017-09-24 22:57:31 -07:00
|
|
|
@end
|