mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-24 04:25:34 +08:00
Compare commits
4 Commits
2.0.0-alph
...
2.0.0-alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e00a08a3dc | ||
|
|
656e82de9f | ||
|
|
1958cf37ea | ||
|
|
75fb558cd3 |
@@ -0,0 +1,30 @@
|
|||||||
|
package com.swmansion.rnscreens;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.Arguments;
|
||||||
|
import com.facebook.react.uimanager.events.Event;
|
||||||
|
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||||
|
|
||||||
|
public class ScreenAppearEvent extends Event<ScreenAppearEvent> {
|
||||||
|
|
||||||
|
public static final String EVENT_NAME = "topAppear";
|
||||||
|
|
||||||
|
public ScreenAppearEvent(int viewId) {
|
||||||
|
super(viewId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEventName() {
|
||||||
|
return EVENT_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getCoalescingKey() {
|
||||||
|
// All events for a given view can be coalesced.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispatch(RCTEventEmitter rctEventEmitter) {
|
||||||
|
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), Arguments.createMap());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.swmansion.rnscreens;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.ContextWrapper;
|
import android.content.ContextWrapper;
|
||||||
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewParent;
|
import android.view.ViewParent;
|
||||||
|
|
||||||
@@ -22,11 +23,14 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
|||||||
|
|
||||||
protected final ArrayList<T> mScreenFragments = new ArrayList<>();
|
protected final ArrayList<T> mScreenFragments = new ArrayList<>();
|
||||||
private final Set<ScreenFragment> mActiveScreenFragments = new HashSet<>();
|
private final Set<ScreenFragment> mActiveScreenFragments = new HashSet<>();
|
||||||
|
private final ArrayList<Runnable> mAfterTransitionRunnables = new ArrayList<>(1);
|
||||||
|
|
||||||
private @Nullable FragmentManager mFragmentManager;
|
private @Nullable FragmentManager mFragmentManager;
|
||||||
private @Nullable FragmentTransaction mCurrentTransaction;
|
private @Nullable FragmentTransaction mCurrentTransaction;
|
||||||
|
private @Nullable FragmentTransaction mProcessingTransaction;
|
||||||
private boolean mNeedUpdate;
|
private boolean mNeedUpdate;
|
||||||
private boolean mIsAttached;
|
private boolean mIsAttached;
|
||||||
|
private boolean mIsTransitioning;
|
||||||
private boolean mLayoutEnqueued = false;
|
private boolean mLayoutEnqueued = false;
|
||||||
|
|
||||||
private final ChoreographerCompat.FrameCallback mFrameCallback = new ChoreographerCompat.FrameCallback() {
|
private final ChoreographerCompat.FrameCallback mFrameCallback = new ChoreographerCompat.FrameCallback() {
|
||||||
@@ -101,6 +105,36 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
|||||||
markUpdated();
|
markUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startViewTransition(View view) {
|
||||||
|
super.startViewTransition(view);
|
||||||
|
mIsTransitioning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endViewTransition(View view) {
|
||||||
|
super.endViewTransition(view);
|
||||||
|
if (mIsTransitioning) {
|
||||||
|
mIsTransitioning = false;
|
||||||
|
notifyTransitionFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTransitioning() {
|
||||||
|
return mIsTransitioning || mProcessingTransaction != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postAfterTransition(Runnable runnable) {
|
||||||
|
mAfterTransitionRunnables.add(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void notifyTransitionFinished() {
|
||||||
|
for (int i = 0, size = mAfterTransitionRunnables.size(); i < size; i++) {
|
||||||
|
mAfterTransitionRunnables.get(i).run();
|
||||||
|
}
|
||||||
|
mAfterTransitionRunnables.clear();
|
||||||
|
}
|
||||||
|
|
||||||
protected int getScreenCount() {
|
protected int getScreenCount() {
|
||||||
return mScreenFragments.size();
|
return mScreenFragments.size();
|
||||||
}
|
}
|
||||||
@@ -159,6 +193,19 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
|||||||
|
|
||||||
protected void tryCommitTransaction() {
|
protected void tryCommitTransaction() {
|
||||||
if (mCurrentTransaction != null) {
|
if (mCurrentTransaction != null) {
|
||||||
|
final FragmentTransaction transaction = mCurrentTransaction;
|
||||||
|
mProcessingTransaction = transaction;
|
||||||
|
mProcessingTransaction.runOnCommit(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (mProcessingTransaction == transaction) {
|
||||||
|
// we need to take into account that commit is initiated with some other transaction while
|
||||||
|
// the previous one is still processing. In this case mProcessingTransaction gets overwritten
|
||||||
|
// and we don't want to set it to null until the second transaction is finished.
|
||||||
|
mProcessingTransaction = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
mCurrentTransaction.commitAllowingStateLoss();
|
mCurrentTransaction.commitAllowingStateLoss();
|
||||||
mCurrentTransaction = null;
|
mCurrentTransaction = null;
|
||||||
}
|
}
|
||||||
@@ -184,6 +231,10 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
|||||||
return screenFragment.getScreen().isActive();
|
return screenFragment.getScreen().isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean hasScreen(ScreenFragment screenFragment) {
|
||||||
|
return mScreenFragments.contains(screenFragment);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onAttachedToWindow() {
|
protected void onAttachedToWindow() {
|
||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
|
|||||||
@@ -7,12 +7,10 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.uimanager.UIManagerModule;
|
import com.facebook.react.uimanager.UIManagerModule;
|
||||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
|
||||||
|
|
||||||
public class ScreenFragment extends Fragment {
|
public class ScreenFragment extends Fragment {
|
||||||
|
|
||||||
@@ -39,12 +37,39 @@ public class ScreenFragment extends Fragment {
|
|||||||
return mScreenView;
|
return mScreenView;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void dispatchOnAppear() {
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
((ReactContext) mScreenView.getContext())
|
((ReactContext) mScreenView.getContext())
|
||||||
.getNativeModule(UIManagerModule.class)
|
.getNativeModule(UIManagerModule.class)
|
||||||
.getEventDispatcher()
|
.getEventDispatcher()
|
||||||
.dispatchEvent(new ScreenDismissedEvent(mScreenView.getId()));
|
.dispatchEvent(new ScreenAppearEvent(mScreenView.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
ScreenContainer container = mScreenView.getContainer();
|
||||||
|
if (container.isTransitioning()) {
|
||||||
|
container.postAfterTransition(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
dispatchOnAppear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dispatchOnAppear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
ScreenContainer container = mScreenView.getContainer();
|
||||||
|
if (container == null || !container.hasScreen(this)) {
|
||||||
|
// we only send dismissed even when the screen has been removed from its container
|
||||||
|
((ReactContext) mScreenView.getContext())
|
||||||
|
.getNativeModule(UIManagerModule.class)
|
||||||
|
.getEventDispatcher()
|
||||||
|
.dispatchEvent(new ScreenDismissedEvent(mScreenView.getId()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,6 +97,11 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
|||||||
super.removeScreenAt(index);
|
super.removeScreenAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean hasScreen(ScreenFragment screenFragment) {
|
||||||
|
return super.hasScreen(screenFragment) && !mDismissed.contains(screenFragment);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onUpdate() {
|
protected void onUpdate() {
|
||||||
// remove all screens previously on stack
|
// remove all screens previously on stack
|
||||||
@@ -128,19 +133,15 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (ScreenStackFragment screen : mScreenFragments) {
|
for (ScreenStackFragment screen : mScreenFragments) {
|
||||||
// add all new views that weren't on stack before
|
|
||||||
if (!mStack.contains(screen) && !mDismissed.contains(screen)) {
|
|
||||||
getOrCreateTransaction().add(getId(), screen);
|
|
||||||
}
|
|
||||||
// detach all screens that should not be visible
|
// detach all screens that should not be visible
|
||||||
if (screen != newTop && screen != belowTop && !mDismissed.contains(screen)) {
|
if (screen != newTop && screen != belowTop && !mDismissed.contains(screen)) {
|
||||||
getOrCreateTransaction().hide(screen);
|
getOrCreateTransaction().remove(screen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// attach "below top" screen if set
|
// attach "below top" screen if set
|
||||||
if (belowTop != null) {
|
if (belowTop != null && !belowTop.isAdded()) {
|
||||||
final ScreenStackFragment top = newTop;
|
final ScreenStackFragment top = newTop;
|
||||||
getOrCreateTransaction().show(belowTop).runOnCommit(new Runnable() {
|
getOrCreateTransaction().add(getId(), belowTop).runOnCommit(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
top.getScreen().bringToFront();
|
top.getScreen().bringToFront();
|
||||||
@@ -148,8 +149,8 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newTop != null) {
|
if (newTop != null && !newTop.isAdded()) {
|
||||||
getOrCreateTransaction().show(newTop);
|
getOrCreateTransaction().add(getId(), newTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mStack.contains(newTop)) {
|
if (!mStack.contains(newTop)) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public class ScreenStackFragment extends ScreenFragment {
|
|||||||
private AppBarLayout mAppBarLayout;
|
private AppBarLayout mAppBarLayout;
|
||||||
private Toolbar mToolbar;
|
private Toolbar mToolbar;
|
||||||
private boolean mShadowHidden;
|
private boolean mShadowHidden;
|
||||||
|
private CoordinatorLayout mScreenRootView;
|
||||||
|
|
||||||
@SuppressLint("ValidFragment")
|
@SuppressLint("ValidFragment")
|
||||||
public ScreenStackFragment(Screen screenView) {
|
public ScreenStackFragment(Screen screenView) {
|
||||||
@@ -59,10 +60,7 @@ public class ScreenStackFragment extends ScreenFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private CoordinatorLayout configureView() {
|
||||||
public View onCreateView(LayoutInflater inflater,
|
|
||||||
@Nullable ViewGroup container,
|
|
||||||
@Nullable Bundle savedInstanceState) {
|
|
||||||
CoordinatorLayout view = new CoordinatorLayout(getContext());
|
CoordinatorLayout view = new CoordinatorLayout(getContext());
|
||||||
CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams(
|
CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams(
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
|
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
|
||||||
@@ -87,6 +85,17 @@ public class ScreenStackFragment extends ScreenFragment {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
if (mScreenRootView == null) {
|
||||||
|
mScreenRootView = configureView();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mScreenRootView;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isDismissable() {
|
public boolean isDismissable() {
|
||||||
View child = mScreenView.getChildAt(0);
|
View child = mScreenView.getChildAt(0);
|
||||||
if (child instanceof ScreenStackHeaderConfig) {
|
if (child instanceof ScreenStackHeaderConfig) {
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ public class ScreenViewManager extends ViewGroupManager<Screen> {
|
|||||||
public Map getExportedCustomDirectEventTypeConstants() {
|
public Map getExportedCustomDirectEventTypeConstants() {
|
||||||
return MapBuilder.of(
|
return MapBuilder.of(
|
||||||
ScreenDismissedEvent.EVENT_NAME,
|
ScreenDismissedEvent.EVENT_NAME,
|
||||||
MapBuilder.of("registrationName", "onDismissed"));
|
MapBuilder.of("registrationName", "onDismissed"),
|
||||||
|
ScreenAppearEvent.EVENT_NAME,
|
||||||
|
MapBuilder.of("registrationName", "onAppear"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
StackRouter,
|
StackRouter,
|
||||||
SceneView,
|
SceneView,
|
||||||
StackActions,
|
StackActions,
|
||||||
NavigationActions,
|
|
||||||
createNavigator,
|
createNavigator,
|
||||||
} from '@react-navigation/core';
|
} from '@react-navigation/core';
|
||||||
import { createKeyboardAwareNavigator } from '@react-navigation/native';
|
import { createKeyboardAwareNavigator } from '@react-navigation/native';
|
||||||
@@ -27,14 +26,13 @@ function renderComponentOrThunk(componentOrThunk, props) {
|
|||||||
|
|
||||||
class StackView extends React.Component {
|
class StackView extends React.Component {
|
||||||
_removeScene = route => {
|
_removeScene = route => {
|
||||||
const { navigation } = this.props;
|
this.props.navigation.dispatch(StackActions.pop({ key: route.key }));
|
||||||
navigation.dispatch(
|
};
|
||||||
NavigationActions.back({
|
|
||||||
key: route.key,
|
_onSceneFocus = route => {
|
||||||
immediate: true,
|
this.props.navigation.dispatch(
|
||||||
})
|
StackActions.completeTransition({ toChildKey: route.key })
|
||||||
);
|
);
|
||||||
navigation.dispatch(StackActions.completeTransition());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_renderHeaderConfig = (index, route, descriptor) => {
|
_renderHeaderConfig = (index, route, descriptor) => {
|
||||||
@@ -165,7 +163,7 @@ class StackView extends React.Component {
|
|||||||
transparentCard || options.cardTransparent ? 'transparentModal' : mode;
|
transparentCard || options.cardTransparent ? 'transparentModal' : mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
let stackAnimation = undefined;
|
let stackAnimation;
|
||||||
if (options.animationEnabled === false) {
|
if (options.animationEnabled === false) {
|
||||||
stackAnimation = 'none';
|
stackAnimation = 'none';
|
||||||
}
|
}
|
||||||
@@ -177,6 +175,7 @@ class StackView extends React.Component {
|
|||||||
style={options.cardStyle}
|
style={options.cardStyle}
|
||||||
stackAnimation={stackAnimation}
|
stackAnimation={stackAnimation}
|
||||||
stackPresentation={stackPresentation}
|
stackPresentation={stackPresentation}
|
||||||
|
onAppear={() => this._onSceneFocus(route)}
|
||||||
onDismissed={() => this._removeScene(route)}>
|
onDismissed={() => this._removeScene(route)}>
|
||||||
{this._renderHeaderConfig(index, route, descriptor)}
|
{this._renderHeaderConfig(index, route, descriptor)}
|
||||||
<SceneView
|
<SceneView
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ typedef NS_ENUM(NSInteger, RNSScreenStackAnimation) {
|
|||||||
|
|
||||||
@interface RNSScreenView : RCTView
|
@interface RNSScreenView : RCTView
|
||||||
|
|
||||||
|
@property (nonatomic, copy) RCTDirectEventBlock onAppear;
|
||||||
@property (nonatomic, copy) RCTDirectEventBlock onDismissed;
|
@property (nonatomic, copy) RCTDirectEventBlock onDismissed;
|
||||||
@property (weak, nonatomic) UIView<RNSScreenContainerDelegate> *reactSuperview;
|
@property (weak, nonatomic) UIView<RNSScreenContainerDelegate> *reactSuperview;
|
||||||
@property (nonatomic, retain) UIViewController *controller;
|
@property (nonatomic, retain) UIViewController *controller;
|
||||||
|
|||||||
@@ -135,6 +135,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)notifyAppear
|
||||||
|
{
|
||||||
|
if (self.onAppear) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
if (self.onAppear) {
|
||||||
|
self.onAppear(nil);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)isMountedUnderScreenOrReactRoot
|
- (BOOL)isMountedUnderScreenOrReactRoot
|
||||||
{
|
{
|
||||||
for (UIView *parent = self.superview; parent != nil; parent = parent.superview) {
|
for (UIView *parent = self.superview; parent != nil; parent = parent.superview) {
|
||||||
@@ -235,6 +246,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)viewDidAppear:(BOOL)animated
|
||||||
|
{
|
||||||
|
[super viewDidAppear:animated];
|
||||||
|
[((RNSScreenView *)self.view) notifyAppear];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)notifyFinishTransitioning
|
- (void)notifyFinishTransitioning
|
||||||
{
|
{
|
||||||
[_previousFirstResponder becomeFirstResponder];
|
[_previousFirstResponder becomeFirstResponder];
|
||||||
@@ -258,6 +275,7 @@ RCT_EXPORT_MODULE()
|
|||||||
RCT_EXPORT_VIEW_PROPERTY(active, BOOL)
|
RCT_EXPORT_VIEW_PROPERTY(active, BOOL)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(stackPresentation, RNSScreenStackPresentation)
|
RCT_EXPORT_VIEW_PROPERTY(stackPresentation, RNSScreenStackPresentation)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(stackAnimation, RNSScreenStackAnimation)
|
RCT_EXPORT_VIEW_PROPERTY(stackAnimation, RNSScreenStackAnimation)
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(onAppear, RCTDirectEventBlock);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(onDismissed, RCTDirectEventBlock);
|
RCT_EXPORT_VIEW_PROPERTY(onDismissed, RCTDirectEventBlock);
|
||||||
|
|
||||||
- (UIView *)view
|
- (UIView *)view
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#import <React/RCTUIManagerObserverCoordinator.h>
|
#import <React/RCTUIManagerObserverCoordinator.h>
|
||||||
#import "RNSScreenContainer.h"
|
#import "RNSScreenContainer.h"
|
||||||
|
|
||||||
@interface RNSScreenStackView : UIView <RNSScreenContainerDelegate>
|
@interface RNSScreenStackView : UIView <RNSScreenContainerDelegate, RCTInvalidating>
|
||||||
|
|
||||||
- (void)markChildUpdated;
|
- (void)markChildUpdated;
|
||||||
- (void)didUpdateChildren;
|
- (void)didUpdateChildren;
|
||||||
|
|||||||
@@ -143,31 +143,48 @@
|
|||||||
NSMutableArray<UIViewController *> *controllersToRemove = [NSMutableArray arrayWithArray:_presentedModals];
|
NSMutableArray<UIViewController *> *controllersToRemove = [NSMutableArray arrayWithArray:_presentedModals];
|
||||||
[controllersToRemove removeObjectsInArray:controllers];
|
[controllersToRemove removeObjectsInArray:controllers];
|
||||||
|
|
||||||
// presenting new controllers
|
// find bottom-most controller that should stay on the stack for the duration of transition
|
||||||
for (UIViewController *newController in newControllers) {
|
NSUInteger changeRootIndex = 0;
|
||||||
[_presentedModals addObject:newController];
|
UIViewController *changeRootController = _controller;
|
||||||
if (_controller.presentedViewController != nil) {
|
for (NSUInteger i = 0; i < MIN(_presentedModals.count, controllers.count); i++) {
|
||||||
[_controller.presentedViewController presentViewController:newController animated:YES completion:nil];
|
if (_presentedModals[i] == controllers[i]) {
|
||||||
|
changeRootController = controllers[i];
|
||||||
|
changeRootIndex = i + 1;
|
||||||
} else {
|
} else {
|
||||||
[_controller presentViewController:newController animated:YES completion:nil];
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hiding old controllers
|
// we verify that controllers added on top of changeRootIndex are all new. Unfortunately modal
|
||||||
for (UIViewController *controller in [controllersToRemove reverseObjectEnumerator]) {
|
// VCs cannot be reshuffled (there are some visual glitches when we try to dismiss then show as
|
||||||
[_presentedModals removeObject:controller];
|
// even non-animated dismissal has delay and updates the screen several times)
|
||||||
if (controller.presentedViewController != nil) {
|
for (NSUInteger i = changeRootIndex; i < controllers.count; i++) {
|
||||||
UIViewController *restore = controller.presentedViewController;
|
if ([_presentedModals containsObject:controllers[i]]) {
|
||||||
UIViewController *parent = controller.presentingViewController;
|
RCTAssert(false, @"Modally presented controllers are being reshuffled, this is not allowed");
|
||||||
[controller dismissViewControllerAnimated:NO completion:^{
|
|
||||||
[parent dismissViewControllerAnimated:NO completion:^{
|
|
||||||
[parent presentViewController:restore animated:NO completion:nil];
|
|
||||||
}];
|
|
||||||
}];
|
|
||||||
} else {
|
|
||||||
[controller.presentingViewController dismissViewControllerAnimated:YES completion:nil];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void (^finish)(void) = ^{
|
||||||
|
UIViewController *previous = changeRootController;
|
||||||
|
for (NSUInteger i = changeRootIndex; i < controllers.count; i++) {
|
||||||
|
UIViewController *next = controllers[i];
|
||||||
|
[previous presentViewController:next
|
||||||
|
animated:(i == controllers.count - 1)
|
||||||
|
completion:nil];
|
||||||
|
previous = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self->_presentedModals removeAllObjects];
|
||||||
|
[self->_presentedModals addObjectsFromArray:controllers];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (changeRootController.presentedViewController) {
|
||||||
|
[changeRootController
|
||||||
|
dismissViewControllerAnimated:(changeRootIndex == controllers.count)
|
||||||
|
completion:finish];
|
||||||
|
} else {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPushViewControllers:(NSArray<UIViewController *> *)controllers
|
- (void)setPushViewControllers:(NSArray<UIViewController *> *)controllers
|
||||||
@@ -244,12 +261,18 @@
|
|||||||
_controller.view.frame = self.bounds;
|
_controller.view.frame = self.bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)invalidate
|
||||||
|
{
|
||||||
|
for (UIViewController *controller in _presentedModals) {
|
||||||
|
[controller dismissViewControllerAnimated:NO completion:nil];
|
||||||
|
}
|
||||||
|
[_presentedModals removeAllObjects];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)dismissOnReload
|
- (void)dismissOnReload
|
||||||
{
|
{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
for (UIViewController *controller in self->_presentedModals) {
|
[self invalidate];
|
||||||
[controller dismissViewControllerAnimated:NO completion:nil];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-native-screens",
|
"name": "react-native-screens",
|
||||||
"version": "2.0.0-alpha.16",
|
"version": "2.0.0-alpha.18",
|
||||||
"description": "First incomplete navigation solution for your react-native app.",
|
"description": "First incomplete navigation solution for your react-native app.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node node_modules/react-native/local-cli/cli.js start",
|
"start": "node node_modules/react-native/local-cli/cli.js start",
|
||||||
|
|||||||
Reference in New Issue
Block a user