mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-03-29 00:38:26 +08:00
Compare commits
8 Commits
2.0.0-alph
...
2.0.0-alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da9426b4b9 | ||
|
|
4169fad8b3 | ||
|
|
4f8efd2873 | ||
|
|
cbc86bb6d8 | ||
|
|
0927e03687 | ||
|
|
efaf0cd125 | ||
|
|
21e6a9732a | ||
|
|
31192250e1 |
@@ -23,6 +23,7 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
||||
protected final ArrayList<T> mScreenFragments = new ArrayList<>();
|
||||
private final Set<ScreenFragment> mActiveScreenFragments = new HashSet<>();
|
||||
|
||||
private @Nullable FragmentManager mFragmentManager;
|
||||
private @Nullable FragmentTransaction mCurrentTransaction;
|
||||
private boolean mNeedUpdate;
|
||||
private boolean mIsAttached;
|
||||
@@ -108,11 +109,18 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
||||
return mScreenFragments.get(index).getScreen();
|
||||
}
|
||||
|
||||
protected final FragmentActivity findRootFragmentActivity() {
|
||||
private FragmentManager findFragmentManager() {
|
||||
ViewParent parent = this;
|
||||
while (!(parent instanceof ReactRootView) && parent.getParent() != null) {
|
||||
// We traverse view hierarchy up until we find screen parent or a root view
|
||||
while (!(parent instanceof ReactRootView || parent instanceof Screen) && parent.getParent() != null) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
// If parent is of type Screen it means we are inside a nested fragment structure.
|
||||
// Otherwise we expect to connect directly with root view and get root fragment manager
|
||||
if (parent instanceof Screen) {
|
||||
return ((Screen) parent).getFragment().getChildFragmentManager();
|
||||
}
|
||||
|
||||
// we expect top level view to be of type ReactRootView, this isn't really necessary but in order
|
||||
// to find root view we test if parent is null. This could potentially happen also when the view
|
||||
// is detached from the hierarchy and that test would not correctly indicate the root view. So
|
||||
@@ -131,11 +139,14 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
||||
throw new IllegalStateException(
|
||||
"In order to use RNScreens components your app's activity need to extend ReactFragmentActivity or ReactCompatActivity");
|
||||
}
|
||||
return (FragmentActivity) context;
|
||||
return ((FragmentActivity) context).getSupportFragmentManager();
|
||||
}
|
||||
|
||||
protected FragmentManager getFragmentManager() {
|
||||
return findRootFragmentActivity().getSupportFragmentManager();
|
||||
protected final FragmentManager getFragmentManager() {
|
||||
if (mFragmentManager == null) {
|
||||
mFragmentManager = findFragmentManager();
|
||||
}
|
||||
return mFragmentManager;
|
||||
}
|
||||
|
||||
protected FragmentTransaction getOrCreateTransaction() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.swmansion.rnscreens;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
@@ -30,6 +31,15 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
}
|
||||
};
|
||||
|
||||
private final FragmentManager.FragmentLifecycleCallbacks mLifecycleCallbacks = new FragmentManager.FragmentLifecycleCallbacks() {
|
||||
@Override
|
||||
public void onFragmentResumed(FragmentManager fm, Fragment f) {
|
||||
if (mTopScreen == f) {
|
||||
setupBackHandlerIfNeeded(mTopScreen);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public ScreenStack(Context context) {
|
||||
super(context);
|
||||
}
|
||||
@@ -61,16 +71,23 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
getFragmentManager().removeOnBackStackChangedListener(mBackStackListener);
|
||||
getFragmentManager().popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
FragmentManager fm = getFragmentManager();
|
||||
fm.removeOnBackStackChangedListener(mBackStackListener);
|
||||
getFragmentManager().unregisterFragmentLifecycleCallbacks(mLifecycleCallbacks);
|
||||
if (!fm.isStateSaved()) {
|
||||
// state save means that the container where fragment manager was installed has been unmounted.
|
||||
// This could happen as a result of dismissing nested stack. In such a case we don't need to
|
||||
// reset back stack as it'd result in a crash caused by the fact the fragment manager is no
|
||||
// longer attached.
|
||||
fm.popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if (mTopScreen != null) {
|
||||
setupBackHandlerIfNeeded(mTopScreen);
|
||||
}
|
||||
getFragmentManager().registerFragmentLifecycleCallbacks(mLifecycleCallbacks, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,7 +105,11 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
getOrCreateTransaction().remove(screen);
|
||||
}
|
||||
}
|
||||
ScreenStackFragment newTop = null;
|
||||
|
||||
// When going back from a nested stack with a single screen on it, we may hit an edge case
|
||||
// when all screens are dismissed and no screen is to be displayed on top. We need to gracefully
|
||||
// handle the case of newTop being NULL, which happens in several places below
|
||||
ScreenStackFragment newTop = null; // newTop is nullable, see the above comment ^
|
||||
ScreenStackFragment belowTop = null; // this is only set if newTop has TRANSPARENT_MODAL presentation mode
|
||||
|
||||
for (int i = mScreenFragments.size() - 1; i >= 0; i--) {
|
||||
@@ -106,7 +127,6 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (ScreenStackFragment screen : mScreenFragments) {
|
||||
// add all new views that weren't on stack before
|
||||
if (!mStack.contains(screen) && !mDismissed.contains(screen)) {
|
||||
@@ -127,7 +147,10 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
}
|
||||
});
|
||||
}
|
||||
getOrCreateTransaction().show(newTop);
|
||||
|
||||
if (newTop != null) {
|
||||
getOrCreateTransaction().show(newTop);
|
||||
}
|
||||
|
||||
if (!mStack.contains(newTop)) {
|
||||
// if new top screen wasn't on stack we do "open animation" so long it is not the very first screen on stack
|
||||
@@ -165,7 +188,9 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
|
||||
tryCommitTransaction();
|
||||
|
||||
setupBackHandlerIfNeeded(mTopScreen);
|
||||
if (mTopScreen != null) {
|
||||
setupBackHandlerIfNeeded(mTopScreen);
|
||||
}
|
||||
|
||||
for (ScreenStackFragment screen : mStack) {
|
||||
screen.onStackUpdate();
|
||||
@@ -192,6 +217,12 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
* that case we want the parent navigator or activity handler to take over.
|
||||
*/
|
||||
private void setupBackHandlerIfNeeded(ScreenStackFragment topScreen) {
|
||||
if (!mTopScreen.isResumed()) {
|
||||
// if the top fragment is not in a resumed state, adding back stack transaction would throw.
|
||||
// In such a case we skip installing back handler and use FragmentLifecycleCallbacks to get
|
||||
// notified when it gets resumed so that we can install the handler.
|
||||
return;
|
||||
}
|
||||
getFragmentManager().removeOnBackStackChangedListener(mBackStackListener);
|
||||
getFragmentManager().popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
ScreenStackFragment firstScreen = null;
|
||||
@@ -208,6 +239,7 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
.hide(topScreen)
|
||||
.show(topScreen)
|
||||
.addToBackStack(BACK_STACK_TAG)
|
||||
.setPrimaryNavigationFragment(topScreen)
|
||||
.commitAllowingStateLoss();
|
||||
getFragmentManager().addOnBackStackChangedListener(mBackStackListener);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class ScreenStackHeaderConfig extends ViewGroup {
|
||||
private String mTitle;
|
||||
private int mTitleColor;
|
||||
private String mTitleFontFamily;
|
||||
private int mTitleFontSize;
|
||||
private float mTitleFontSize;
|
||||
private int mBackgroundColor;
|
||||
private boolean mIsHidden;
|
||||
private boolean mGestureEnabled = true;
|
||||
@@ -258,7 +258,7 @@ public class ScreenStackHeaderConfig extends ViewGroup {
|
||||
mTitleFontFamily = titleFontFamily;
|
||||
}
|
||||
|
||||
public void setTitleFontSize(int titleFontSize) {
|
||||
public void setTitleFontSize(float titleFontSize) {
|
||||
mTitleFontSize = titleFontSize;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,8 @@ public class ScreenStackHeaderConfigViewManager extends ViewGroupManager<ScreenS
|
||||
}
|
||||
|
||||
@ReactProp(name = "titleFontSize")
|
||||
public void setTitleFontSize(ScreenStackHeaderConfig config, double titleFontSizeSP) {
|
||||
config.setTitleFontSize((int) PixelUtil.toPixelFromSP(titleFontSizeSP));
|
||||
public void setTitleFontSize(ScreenStackHeaderConfig config, float titleFontSize) {
|
||||
config.setTitleFontSize(titleFontSize);
|
||||
}
|
||||
|
||||
@ReactProp(name = "titleColor", customType = "Color")
|
||||
|
||||
@@ -48,6 +48,7 @@ class StackView extends React.Component {
|
||||
headerTitleStyle,
|
||||
headerBackTitleStyle,
|
||||
headerBackTitle,
|
||||
headerBackTitleVisible,
|
||||
headerTintColor,
|
||||
gestureEnabled,
|
||||
largeTitle,
|
||||
@@ -69,7 +70,7 @@ class StackView extends React.Component {
|
||||
titleFontFamily: headerTitleStyle && headerTitleStyle.fontFamily,
|
||||
titleColor: headerTintColor,
|
||||
titleFontSize: headerTitleStyle && headerTitleStyle.fontSize,
|
||||
backTitle: headerBackTitle,
|
||||
backTitle: headerBackTitleVisible === false ? '' : headerBackTitle,
|
||||
backTitleFontFamily:
|
||||
headerBackTitleStyle && headerBackTitleStyle.fontFamily,
|
||||
backTitleFontSize: headerBackTitleStyle && headerBackTitleStyle.fontSize,
|
||||
@@ -154,7 +155,7 @@ class StackView extends React.Component {
|
||||
};
|
||||
|
||||
_renderScene = (index, route, descriptor) => {
|
||||
const { navigation, getComponent } = descriptor;
|
||||
const { navigation, getComponent, options } = descriptor;
|
||||
const { mode, transparentCard } = this.props.navigationConfig;
|
||||
const SceneComponent = getComponent();
|
||||
|
||||
@@ -167,7 +168,7 @@ class StackView extends React.Component {
|
||||
return (
|
||||
<Screen
|
||||
key={`screen_${route.key}`}
|
||||
style={StyleSheet.absoluteFill}
|
||||
style={options.cardStyle}
|
||||
stackPresentation={stackPresentation}
|
||||
onDismissed={() => this._removeScene(route)}>
|
||||
{this._renderHeaderConfig(index, route, descriptor)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-screens",
|
||||
"version": "2.0.0-alpha.12",
|
||||
"version": "2.0.0-alpha.14",
|
||||
"description": "First incomplete navigation solution for your react-native app.",
|
||||
"scripts": {
|
||||
"start": "node node_modules/react-native/local-cli/cli.js start",
|
||||
|
||||
Reference in New Issue
Block a user