如何在React Native中用动画实现状态更新时的屏幕滑动切换效果
React Native 实现问卷页右滑覆盖转场效果方案
现有代码问题排查
- 动画映射错误:直接将0-1范围的动画值绑定到
translateX属性,仅会产生1px位移,无法出现整屏滑入效果 - 状态更新逻辑错误:先更新
activeIndex再触发动画,会导致旧内容直接被替换,无法看到转场过程 - 缺少双视图层级控制:要实现新内容覆盖旧内容的效果,需要同时保留新旧两个问题视图,控制前后层级和各自的位移属性
完整实现代码
import { View, Text, Button, Animated, Dimensions, StyleSheet } from 'react-native' import { useState, useRef } from 'react' // 获取屏幕宽度作为动画偏移基准 const SCREEN_WIDTH = Dimensions.get('window').width // 转场时长和React Navigation默认时长保持一致 const TRANSITION_DURATION = 300 const QuestionScreen = () => { const [activeIndex, setActiveIndex] = useState(0) // 存储上一个问题的索引,用于渲染退场的旧内容 const [previousIndex, setPreviousIndex] = useState(null) // 动画值用ref存,不需要触发重渲染 const slideAnim = useRef(new Animated.Value(0)).current const onClickNext = () => { // 防止动画过程中重复点击 if (previousIndex !== null) return // 先存储当前索引作为待退场的旧内容索引 setPreviousIndex(activeIndex) // 重置动画值为屏幕宽度,新内容初始在屏幕右侧外部 slideAnim.setValue(SCREEN_WIDTH) // 更新为新的问题索引 const newIndex = activeIndex + 1 setActiveIndex(newIndex) // 启动滑入动画 Animated.timing(slideAnim, { toValue: 0, duration: TRANSITION_DURATION, useNativeDriver: true, }).start(() => { // 动画结束后清空旧索引,释放资源 setPreviousIndex(null) }) } // 这里替换为你自己的问题文本获取逻辑 const getQuestionText = (index) => { return `第${index + 1}题的问题内容` } return ( <View style={styles.container}> {/* 渲染旧的问题内容(如果存在),在视图底层 */} {previousIndex !== null && ( <View style={styles.questionContainer}> <Text>{getQuestionText(previousIndex)}</Text> </View> )} {/* 渲染新的问题内容,在视图顶层,绑定滑入动画 */} <Animated.View style={[ styles.questionContainer, { transform: [{ translateX: slideAnim }] } ]} > <Text>{getQuestionText(activeIndex)}</Text> {/* 你的下一步按钮 */} <Button title="下一步" onPress={onClickNext} /> </Animated.View> </View> ) } const styles = StyleSheet.create({ container: { flex: 1, position: 'relative' }, questionContainer: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: '#fff', // 必须设置背景色,否则会透出下层内容 padding: 20 } })
效果适配说明
- 如果需要和React Navigation默认转场完全一致,可以给旧内容也添加位移动画,让旧内容随新内容滑入同步向左偏移20%屏幕宽度即可
- 如果需要实现上一题的左滑入场效果,只需把动画初始值设置为
-SCREEN_WIDTH即可
内容的提问来源于stack exchange,提问作者Yener
相关产品推荐
相关产品推荐

