mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-02-26 22:38:23 +08:00
Compare commits
11 Commits
2.0.0-beta
...
2.0.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdbf4e463f | ||
|
|
4e8d13dc72 | ||
|
|
d3b6bea594 | ||
|
|
b29e634e26 | ||
|
|
f2caf02d8c | ||
|
|
c8845cbb6a | ||
|
|
9bf2edd405 | ||
|
|
748cdc6fba | ||
|
|
89cf0b7e52 | ||
|
|
db4733ad05 | ||
|
|
8952e698d2 |
@@ -67,9 +67,9 @@ yarn add react-native-screens
|
||||
2. Open your App.js file and add the following snippet somewhere near the top of the file (e.g. right after import statements):
|
||||
|
||||
```js
|
||||
import { useScreens } from 'react-native-screens';
|
||||
import { enableScreens } from 'react-native-screens';
|
||||
|
||||
useScreens();
|
||||
enableScreens();
|
||||
```
|
||||
|
||||
3. That's all 🎉 – enjoy faster navigation in your Expo app. Keep in mind screens are in pretty early phase so please report if you discover some issues.
|
||||
|
||||
@@ -218,6 +218,12 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
// if there are pending transactions and this view is about to get detached we need to perform
|
||||
// them here as otherwise fragment manager will crash because it won't be able to find container
|
||||
// view.
|
||||
if (mFragmentManager != null && !mFragmentManager.isDestroyed()) {
|
||||
mFragmentManager.executePendingTransactions();
|
||||
}
|
||||
super.onDetachedFromWindow();
|
||||
mIsAttached = false;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,13 @@
|
||||
#import <React/RCTShadowView.h>
|
||||
#import <React/RCTTouchHandler.h>
|
||||
|
||||
@interface RNSScreenView () <UIAdaptivePresentationControllerDelegate>
|
||||
@interface RNSScreen ()
|
||||
|
||||
- (void)invalidate;
|
||||
|
||||
@end
|
||||
|
||||
@interface RNSScreenView () <UIAdaptivePresentationControllerDelegate, RCTInvalidating>
|
||||
@end
|
||||
|
||||
@implementation RNSScreenView {
|
||||
@@ -46,6 +52,11 @@
|
||||
// subviews
|
||||
}
|
||||
|
||||
- (UIViewController *)reactViewController
|
||||
{
|
||||
return _controller;
|
||||
}
|
||||
|
||||
- (void)updateBounds
|
||||
{
|
||||
[_bridge.uiManager setSize:self.bounds.size forView:self];
|
||||
@@ -120,6 +131,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setGestureEnabled:(BOOL)gestureEnabled
|
||||
{
|
||||
#ifdef __IPHONE_13_0
|
||||
if (@available(iOS 13.0, *)) {
|
||||
_controller.modalInPresentation = !gestureEnabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
_gestureEnabled = gestureEnabled;
|
||||
}
|
||||
|
||||
- (UIView *)reactSuperview
|
||||
{
|
||||
return _reactSuperview;
|
||||
@@ -215,18 +237,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
[_controller invalidate];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RNSScreen {
|
||||
__weak UIView *_view;
|
||||
__weak id _previousFirstResponder;
|
||||
CGRect _lastViewFrame;
|
||||
BOOL disappeared;
|
||||
BOOL invalidated;
|
||||
}
|
||||
|
||||
- (instancetype)initWithView:(UIView *)view
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_view = view;
|
||||
self.view = view;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -257,6 +285,7 @@
|
||||
|
||||
- (void)willMoveToParentViewController:(UIViewController *)parent
|
||||
{
|
||||
[super willMoveToParentViewController:parent];
|
||||
if (parent == nil) {
|
||||
id responder = [self findFirstResponder:self.view];
|
||||
if (responder != nil) {
|
||||
@@ -271,13 +300,24 @@
|
||||
if (self.parentViewController == nil && self.presentingViewController == nil) {
|
||||
// screen dismissed, send event
|
||||
[((RNSScreenView *)self.view) notifyDismissed];
|
||||
_view = self.view;
|
||||
}
|
||||
disappeared = YES;
|
||||
if (invalidated) {
|
||||
self.view = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
if (disappeared) {
|
||||
self.view = nil;
|
||||
}
|
||||
invalidated = YES;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
disappeared = NO;
|
||||
[super viewDidAppear:animated];
|
||||
[((RNSScreenView *)self.view) notifyAppear];
|
||||
}
|
||||
@@ -288,14 +328,6 @@
|
||||
_previousFirstResponder = nil;
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
if (_view != nil) {
|
||||
self.view = _view;
|
||||
_view = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RNSScreenManager
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface RNSScreenContainerView ()
|
||||
@interface RNSScreenContainerView () <RCTInvalidating>
|
||||
|
||||
@property (nonatomic, retain) UIViewController *controller;
|
||||
@property (nonatomic, retain) NSMutableSet<RNSScreenView *> *activeScreens;
|
||||
@@ -54,7 +54,6 @@
|
||||
{
|
||||
subview.reactSuperview = self;
|
||||
[_reactSubviews insertObject:subview atIndex:atIndex];
|
||||
subview.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
|
||||
}
|
||||
|
||||
- (void)removeReactSubview:(RNSScreenView *)subview
|
||||
@@ -68,6 +67,11 @@
|
||||
return _reactSubviews;
|
||||
}
|
||||
|
||||
- (UIViewController *)reactViewController
|
||||
{
|
||||
return _controller;
|
||||
}
|
||||
|
||||
- (void)detachScreen:(RNSScreenView *)screen
|
||||
{
|
||||
[screen.controller willMoveToParentViewController:nil];
|
||||
@@ -79,6 +83,7 @@
|
||||
- (void)attachScreen:(RNSScreenView *)screen
|
||||
{
|
||||
[_controller addChildViewController:screen.controller];
|
||||
screen.controller.view.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
|
||||
[_controller.view addSubview:screen.controller.view];
|
||||
[screen.controller didMoveToParentViewController:_controller];
|
||||
[_activeScreens addObject:screen];
|
||||
@@ -155,10 +160,22 @@
|
||||
[self markChildUpdated];
|
||||
}
|
||||
|
||||
- (void)didMoveToWindow
|
||||
{
|
||||
if (self.window) {
|
||||
[self reactAddControllerToClosestParent:_controller];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
[_controller willMoveToParentViewController:nil];
|
||||
[_controller removeFromParentViewController];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
[self reactAddControllerToClosestParent:_controller];
|
||||
_controller.view.frame = self.bounds;
|
||||
for (RNSScreenView *subview in _reactSubviews) {
|
||||
subview.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
_dismissedScreens = [NSMutableSet new];
|
||||
_controller = [[UINavigationController alloc] init];
|
||||
_controller.delegate = self;
|
||||
[self addSubview:_controller.view];
|
||||
_controller.interactivePopGestureRecognizer.delegate = self;
|
||||
|
||||
// we have to initialize viewControllers with a non empty array for
|
||||
@@ -49,6 +48,11 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIViewController *)reactViewController
|
||||
{
|
||||
return _controller;
|
||||
}
|
||||
|
||||
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
|
||||
{
|
||||
UIView *view = viewController.view;
|
||||
@@ -174,10 +178,35 @@
|
||||
{
|
||||
[super didMoveToWindow];
|
||||
if (self.window) {
|
||||
// when stack is added to a window we try to update push and modal view controllers. It is
|
||||
// because modal operations are blocked by UIKit when parent VC is not mounted, so we need
|
||||
// to redo them when the stack is attached.
|
||||
// when stack is attached to a window we do two things:
|
||||
// 1) we run updateContainer – we do this because we want push view controllers to be installed
|
||||
// before the VC is mounted. If we do that after it is added to parent the push updates operations
|
||||
// are going to be blocked by UIKit.
|
||||
// 2) we add navigation VS to parent – this is needed for the VC lifecycle events to be dispatched
|
||||
// properly
|
||||
// 3) we again call updateContainer – this time we do this to open modal controllers. Modals
|
||||
// won't open in (1) because they require navigator to be added to parent. We handle that case
|
||||
// gracefully in setModalViewControllers and can retry opening at any point.
|
||||
[self updateContainer];
|
||||
[self reactAddControllerToClosestParent:_controller];
|
||||
[self updateContainer];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reactAddControllerToClosestParent:(UIViewController *)controller
|
||||
{
|
||||
if (!controller.parentViewController) {
|
||||
UIView *parentView = (UIView *)self.reactSuperview;
|
||||
while (parentView) {
|
||||
if (parentView.reactViewController) {
|
||||
[parentView.reactViewController addChildViewController:controller];
|
||||
[self addSubview:controller.view];
|
||||
[controller didMoveToParentViewController:parentView.reactViewController];
|
||||
break;
|
||||
}
|
||||
parentView = (UIView *)parentView.reactSuperview;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +272,8 @@
|
||||
[weakSelf.presentedModals
|
||||
removeObjectsInRange:NSMakeRange(changeRootIndex, oldCount - changeRootIndex)];
|
||||
}
|
||||
if (changeRootController.view.window == nil || changeRootIndex >= controllers.count) {
|
||||
BOOL isAttached = changeRootController.parentViewController != nil || changeRootController.presentingViewController != nil;
|
||||
if (!isAttached || changeRootIndex >= controllers.count) {
|
||||
// if change controller view is not attached, presenting modals will silently fail on iOS.
|
||||
// In such a case we trigger controllers update from didMoveToWindow.
|
||||
// We also don't run any present transitions if changeRootIndex is greater or equal to the size
|
||||
@@ -299,7 +329,7 @@
|
||||
// controller is still there
|
||||
BOOL firstTimePush = ![lastTop isKindOfClass:[RNSScreen class]];
|
||||
|
||||
BOOL shouldAnimate = !firstTimePush && ((RNSScreenView *) lastTop.view).stackAnimation != RNSScreenStackAnimationNone && !_controller.presentedViewController;
|
||||
BOOL shouldAnimate = !firstTimePush && ((RNSScreenView *) lastTop.view).stackAnimation != RNSScreenStackAnimationNone;
|
||||
|
||||
if (firstTimePush) {
|
||||
// nothing pushed yet
|
||||
@@ -358,7 +388,6 @@
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
[self reactAddControllerToClosestParent:_controller];
|
||||
_controller.view.frame = self.bounds;
|
||||
}
|
||||
|
||||
@@ -368,6 +397,8 @@
|
||||
[controller dismissViewControllerAnimated:NO completion:nil];
|
||||
}
|
||||
[_presentedModals removeAllObjects];
|
||||
[_controller willMoveToParentViewController:nil];
|
||||
[_controller removeFromParentViewController];
|
||||
}
|
||||
|
||||
- (void)dismissOnReload
|
||||
|
||||
@@ -275,11 +275,7 @@
|
||||
}
|
||||
|
||||
[navctr setNavigationBarHidden:shouldHide animated:YES];
|
||||
#ifdef __IPHONE_13_0
|
||||
if (@available(iOS 13.0, *)) {
|
||||
vc.modalInPresentation = !config.screenView.gestureEnabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (shouldHide) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "react-native-screens",
|
||||
"version": "2.0.0-beta.8",
|
||||
"description": "First incomplete navigation solution for your react-native app.",
|
||||
"version": "2.0.0-beta.11",
|
||||
"description": "Native navigation primitives for your React Native app.",
|
||||
"scripts": {
|
||||
"start": "node node_modules/react-native/local-cli/cli.js start",
|
||||
"test": "npm run format && npm run lint && npm run test:unit",
|
||||
|
||||
Reference in New Issue
Block a user