说我在StackNavigator应用程序中浏览了4个屏幕,现在我想回到第一个屏幕。似乎有三种不同的方法可以做到这一点,它们会导航到我想要做的地方,但每种方式都有一个循环每个前一个屏幕的动画。
是否有一种干净的方式从SCREEN_D
导航到SCREEN_A
?
换句话说,在SCREEN_C
向后导航时看到SCREEN_B
之前,我不希望看到SCREEN_A
和SCREEN_D
一分钟。 p>
navigation.navigate(SCREEN_A);
...
navigation.navigate(SCREEN_B);
...
navigation.navigate(SCREEN_C);
...
navigation.navigate(SCREEN_D);
三种方法:
1
return this.props.navigation
.dispatch(NavigationActions.reset(
{
index: 0,
actions: [NavigationActions.navigate({ routeName: 'SCREEN_A'})]
}));
2
const {SCREEN_B_KEY} = this.props.navigation.state.params
this.props.navigation.goBack(SCREEN_B_KEY)
3
const defaultGetStateForAction = Navigation.router.getStateForAction;
Navigation.router.getStateForAction = (action, state) =>{
if(action.type === "Navigation/BACK"){
const routes = [
{routeName: 'First'},
];
return {
...state,
routes,
index: 0,
};
}
return defaultGetStateForAction (action,state);
}
答案 0 :(得分:7)
这是一个快速解决方案。 这将在导航(向前或向后)时删除所有过渡。
const Nav = StackNavigator({
Screens
},{
transitionConfig,
navigationOptions
});
在transitionConfig中添加:
const transitionConfig = () => ({
transitionSpec: {
duration: 0,
timing: Animated.timing,
easing: Easing.step0,
},
})
transitionConfig是一个返回一个覆盖默认屏幕转换的对象的函数。 https://reactnavigation.org/docs/navigators/stack
答案 1 :(得分:5)
您可以使用Navigation prop中的popToTop
方法执行此操作。另外,如果您使用的是redux,则应更新Redux integration。
希望这有帮助!
答案 2 :(得分:4)
本机导航具有popToTop
,我们可以像打击一样使用
this.props.navigation.popToTop()
答案 3 :(得分:3)
对于2020 / react-navigation-stack,我在设置StackNavigator时使用以下代码:
import { createStackNavigator, CardStyleInterpolators } from 'react-navigation-stack';
import { Easing } from 'react-native';
const Navigator = createStackNavigator({
// ...
}, {
defaultNavigationOptions: ({ navigation }) => {
const animation = navigation.getParam('_animation');
return {
// ...
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
...(animation === 'back' && {
gestureDirection: 'horizontal-inverted',
}),
...(animation === 'skip' && {
transitionSpec: {
open: { animation: 'timing', config: { duration: 0, easing: Easing.step1 }, },
close: { animation: 'timing', config: { duration: 0, easing: Easing.step0 }, },
},
}),
};
},
});
和_animation参数覆盖动画样式
// replace to a route not in the stack normally creates a forward animation, but
// we want a backwards animation
this.props.navigation.dispatch(
StackActions.replace({ routeName: 'Login', params: { _animation: 'back' } })
);
答案 4 :(得分:0)
还花了一些时间在这上面,让我总结一下我发现的内容,有多种解决方案/解决方法:
CardStackStyleInterpolator
pull request提到的Cristiano Santos似乎已合并。因此,您可以使用此导入加载CardStackStyleInterpolator
:
import CardStackStyleInterpolator from 'react-navigation/src/views/CardStack/CardStackStyleInterpolator'
像这样申请:
const YourStackNavigator = StackNavigator({
Screen1: { screen: Screen1 },
Screen2: { screen: Screen2 },
}, {
transitionConfig: () => ({
screenInterpolator: (props) => CardStackStyleInterpolator.forHorizontal(props)
})
});
就我而言,我只是跳到下一个屏幕:
this.props.navigation.navigate('Modal_AddGoodClass');
但是在我的reducer中,我在触发Modal_AddGoodClass
屏幕时重置了导航器:
const NewExportReceiptNavigationReducer = (state, action) => {
// Default stuff
let newStateBuffer = newState || state;
if (action) {
if (action.type === 'Navigation/NAVIGATE') {
if (action.routeName === 'Modal_AddGoodClass') {
newStateBuffer = {
index: 0,
routes: [
newStateBuffer.routes[newStateBuffer.routes.length - 1]
]
};
}
}
}
return newStateBuffer;
};
module.exports = NewExportReceiptNavigationReducer;
这很有效,除了事实,那仍然是"返回"使用动画而不是"前进"之一。
您还可以找到here一些使用CardStackStyleInterpolator
的示例代码。
getStateForAction
:当Fendrian提及here时,您可以覆盖路由器的getStateForAction
以避免导航器返回。这似乎有效,除了"刷回" iOS上的手势:
Nav = StackNavigator(navScreens, navOptions);
const defaultGetStateForAction = Nav.router.getStateForAction;
Nav.router.getStateForAction = (action, state) => {
if (
state &&
action.type === NavigationActions.BACK &&
(
state.routes[state.index].routeName === 'Login' ||
state.routes[state.index].routeName === 'Main'
)
) {
// Returning null indicates stack end, and triggers exit
return null;
}
return defaultGetStateForAction(action, state);
};
答案 5 :(得分:0)
这是我的工作解决方案,无需创建新路径
即可重置回主页(root)if(this.categoriesNav.state.nav.index >0){
let k = this.categoriesNav.state.nav.routes[1].key;
this.categoriesNav.dispatch(NavigationActions.back({key: k})); }
categoriesNav
引用了我的堆栈导航器
答案 6 :(得分:0)
我认为我得到了本文https://medium.com/async-la/custom-transitions-in-react-navigation-2f759408a053中所述的解决方案,该解决方案说明了导航的工作原理(强烈建议您阅读它,因为它是一本非常速读的书,有助于我更好地理解过渡的工作原理) 。
以下是示例导航器的gif图像,该示例导航器具有平滑的过渡效果,可以来回移动多个屏幕: Navigator Gif (很抱歉,这是一个链接,我没有足够的代表来嵌入视频,所以我必须做一个链接)。但是,这显示了下面源代码的导航器的行为。
基本上,如果要从堆栈上的屏幕4转到1,可以将不透明度2和3设置为0,这样过渡效果就会从4变为1。
这是导航器的源代码:
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import ScreenA from './ScreenA';
import ScreenB from './ScreenB';
import ScreenC from './ScreenC';
import ScreenD from './ScreenD';
const OuterNavigator = createStackNavigator(
{
ScreenA: {
screen: ScreenA,
navigationOptions: {
//Set header stuff here
headerTintColor: "#fff",
headerStyle: {
backgroundColor: '#4444aa',
},
headerTitle: "Screen A"
}
},
ScreenB: {
screen: ScreenB,
navigationOptions: {
headerTintColor: "#fff",
headerStyle: {
backgroundColor: '#44aa44',
},
headerTitle: "Screen B"
}
},
ScreenC: {
screen: ScreenC,
navigationOptions: {
headerTintColor: "#fff",
headerStyle: {
backgroundColor: '#aa4444',
},
headerTitle: "Screen C"
}
},
ScreenD: {
screen: ScreenD,
navigationOptions: {
headerTintColor: "#fff",
headerStyle: {
backgroundColor: '#44aaaa',
},
headerTitle: "Screen D"
}
},
},
{
// Sets initial screen to screen A
initialRouteName: 'ScreenA',
// Can be changed to whatever you prefer
headerMode: 'float',
// This line makes a transparent background so the navigator can be wrapped in a background image
// (this was an issue I struggled with and figured there's a change someone else might be as well)
cardStyle: { backgroundColor: '00000000', shadowColor: '000000' },
transitionConfig: () => ({
// This link exlpains this in detail:
// https://medium.com/async-la/custom-transitions-in-react-navigation-2f759408a053
containerStyle: {
// This also has to do with having a background image
backgroundColor: '00000000',
},
transitionSpec: {
// Sets speed for transition (lower -> faster)
duration: 500,
useNativeDriver: true,
},
screenInterpolator: sceneProps => {
// Parses scene props
const { position, layout, scene, index, scenes } = sceneProps
// Grabs height and width of screen
const toIndex = index
const thisSceneIndex = scene.index
const height = layout.initHeight
const width = layout.initWidth
// Grab index of last screen
const lastSceneIndex = scenes[scenes.length - 1].index
// Calculates change in indices
const deltaScene = (lastSceneIndex - toIndex == 0) ? 1 : (lastSceneIndex - toIndex);
let translateX = position.interpolate({
inputRange: [thisSceneIndex - 1, thisSceneIndex],
// Adjusts how the output get scaled
outputRange: [width / deltaScene, 0],
});
const translateY = position.interpolate({
// Not used, but in the link they use this for vertical transitions
// If you're interested in that this would do it
inputRange: [0, thisSceneIndex],
outputRange: [height, 0]
});
// MAGIC HAPPENS HERE:
// Test whether we're skipping back more than one screen
// and slide from bottom if true
if (lastSceneIndex - toIndex > 1) {
// If you want the screen to which you are transitioning to not move
// have return; in this if block (see link). If you want behaviour as
// shown in the GIF then leave this
if (scene.index === toIndex) {
return { transform: [{ translateX }] }
}
// BIG MAGIC HERE
// Hide all screens in between
if (scene.index !== lastSceneIndex) return { opacity: 0 }
}
return { transform: [{ translateX }] }
},
}),
}
);
例如,假设您的堆栈类似于[A,B,C,D](因此D在顶部)。 lastSceneIndex获取最后一个场景的索引(在本例中为D)。 DeltaScene计算场景的变化量。当一个人返回多于1个屏幕时,DeltaScene只会是= 1。如果您不熟悉translateX的工作方式,强烈建议您阅读上述链接;输出范围为[width / deltaScene,0]的原因是在动画开始之前,屏幕相互堆叠,然后动画缩放将像[A] [B] [C] [D ],其中每个屏幕均以width / deltaScene隔开。在此示例中,deltaScene为3,因此B为A右侧的宽度/ 3,C为2 * A右侧的宽度/ 3,D为3 * width / 3 = A右侧的宽度,其中这就是我们想要的。如果没有deltaScene,D会向右飞3倍,快于A出现在屏幕上的速度,这会带来难看的过渡。
此外,我怀疑有人需要看到它,但以防万一,这是在App.js中使用的方式(该提供程序用于redux,因此,如果您不想处理它,则可以省略)
<Provider store={store}>
<ImageBackground source={require('./assets/background.png')} style={styles.backgroundImage} resizeMode='cover'>
<AppNavigator />
</ImageBackground>
</Provider>
...
const styles = StyleSheet.create({
backgroundImage: {
flex: 1,
}
});
我真的希望这会有所帮助! 我仍然对本机和其他内容还很陌生,因此,如果我犯了任何错误,或者还有进一步改进或解释的空间,请在对我/其他可能看到此情况的人的评论中说出来!