如何在React Native中为登录/登出状态的导航栈切换添加平滑淡入淡出动画?
实现登录/登出状态切换时的淡入淡出导航动画
你当前通过条件渲染Stack.Screen切换导航栈的方式,本质是组件的挂载/卸载,不会触发React Navigation的导航过渡动画,所以需要调整实现逻辑,下面提供两种贴近你iOS原生实现的方案:
方案一:利用React Navigation导航重置+自定义过渡动画
这种方式通过reset动作切换根栈,同时配置导航过渡动画,符合React Navigation的设计逻辑:
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; import { useEffect } from 'react'; const Stack = createStackNavigator(); function App() { const navigationRef = useNavigationContainerRef(); // 监听登录状态变化,重置导航栈 useEffect(() => { const targetRoute = isLoggedIn ? 'HomeStack' : 'Auth'; navigationRef.reset({ index: 0, routes: [{ name: targetRoute }], }); }, [isLoggedIn, navigationRef]); return ( <NavigationContainer ref={navigationRef}> <Stack.Navigator screenOptions={{ headerShown: false }}> <Stack.Screen name="HomeStack" component={HomeStack} options={{ // 自定义淡入淡出插值器 cardStyleInterpolator: ({ current }) => ({ cardStyle: { opacity: current.progress.interpolate({ inputRange: [0, 1], outputRange: [0, 1], }), }, // 关闭默认遮罩层 overlayStyle: { opacity: 0 }, }), // 配置动画时长,和你iOS代码的0.5秒对应 transitionSpec: { open: { animation: 'timing', config: { duration: 500 } }, close: { animation: 'timing', config: { duration: 500 } }, }, }} /> <Stack.Screen name="Auth" component={AuthStack} options={{ cardStyleInterpolator: ({ current }) => ({ cardStyle: { opacity: current.progress.interpolate({ inputRange: [0, 1], outputRange: [0, 1], }), }, overlayStyle: { opacity: 0 }, }), transitionSpec: { open: { animation: 'timing', config: { duration: 500 } }, close: { animation: 'timing', config: { duration: 500 } }, }, }} /> </Stack.Navigator> </NavigationContainer> ); }
方案二:直接对根容器做动画(更贴近你的iOS实现)
这种方式和你Swift代码逻辑完全一致,直接给整个导航容器添加淡入淡出动画,适合完全替换根栈的场景:
import { NavigationContainer } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; import { Animated, useRef, useEffect } from 'react'; const Stack = createStackNavigator(); function App() { // 初始化动画值,根据当前登录状态设置初始透明度 const opacityAnim = useRef(new Animated.Value(isLoggedIn ? 1 : 0)).current; // 登录状态变化时执行动画 useEffect(() => { Animated.timing(opacityAnim, { toValue: isLoggedIn ? 1 : 0, duration: 500, // 和iOS代码的0.5秒匹配 useNativeDriver: true, // 使用原生驱动提升动画性能 }).start(({ finished }) => { // 动画结束后的回调,对应Swift里的completion if (finished) { // 可在此处添加后续逻辑 } }); }, [isLoggedIn]); return ( <Animated.View style={{ flex: 1, opacity: opacityAnim }}> <NavigationContainer> <Stack.Navigator> {isLoggedIn ? ( <Stack.Screen name='HomeStack' component={HomeStack} options={{ headerShown: false }} /> ) : ( <Stack.Screen name='Auth' component={AuthStack} options={{ headerShown: false }} /> )} </Stack.Navigator> </NavigationContainer> </Animated.View> ); }
方案对比
- 方案一:遵循React Navigation导航机制,适合需要保留导航栈状态、或后续有其他导航操作的场景。
- 方案二:逻辑贴近原生iOS实现,直接操作根容器动画,代码简洁,适合完全切换根导航栈的场景。
内容的提问来源于stack exchange,提问作者Anirudha Mahale
相关产品推荐
相关产品推荐

