如何实现React Native条件渲染组件的流畅过渡动画?
如何实现React Native条件渲染组件的流畅过渡动画?
你遇到的问题本质是直接挂载/卸载组件会触发瞬间布局重排,导致下方元素生硬位移。下面提供两种无需硬编码预留空间的可行方案:
方案一:用Animated库实现精准高度过渡
核心思路是始终渲染Tasks组件,通过动画控制外层容器的高度和透明度,从0平滑过渡到组件实际高度,避免直接插入/移除元素。
修改后的代码示例
Home.js:
import React, { useState, useRef, useEffect } from 'react'; import { View, Text, TouchableOpacity, Animated } from 'react-native'; import Tasks from './Tasks'; export default function Home() { const [showmore, setShowmore] = useState(false); // 动画变量:控制容器高度和透明度 const taskHeight = useRef(new Animated.Value(0)).current; const opacity = useRef(new Animated.Value(0)).current; // 存储Tasks组件的实际高度 const [actualTaskHeight, setActualTaskHeight] = useState(0); // 获取Tasks渲染后的真实高度 const handleTaskLayout = (event) => { const { height } = event.nativeEvent.layout; setActualTaskHeight(height); }; // 切换状态时触发动画 useEffect(() => { Animated.parallel([ Animated.timing(taskHeight, { toValue: showmore ? actualTaskHeight : 0, duration: 300, // 动画时长,可自定义 useNativeDriver: false, // height动画不支持原生驱动 }), Animated.timing(opacity, { toValue: showmore ? 1 : 0, duration: 300, useNativeDriver: true, }), ]).start(); }, [showmore, actualTaskHeight]); return ( <View> <View> <Text>Render Something </Text> </View> {/* 用Animated.View包裹Tasks,通过动画控制显示 */} <Animated.View style={{ height: taskHeight, opacity, overflow: 'hidden', // 防止内容在高度为0时溢出 }} > <Tasks onLayout={handleTaskLayout} /> </Animated.View> <TouchableOpacity onPress={() => setShowmore(!showmore)}> <Text>{showmore ? '收起' : '展开'} Button</Text> </TouchableOpacity> </View> ); }
Tasks.js(只需传递onLayout事件):
import React from 'react'; import { View, Text } from 'react-native'; export default function Tasks({ onLayout }) { return ( <View onLayout={onLayout}> <Text> render some more things </Text> <Text> render some more things </Text> <Text> render some more things </Text> <Text> render some more things </Text> <Text> render some more things </Text> </View> ); }
方案二:用LayoutAnimation实现全局布局过渡
如果不需要精准控制单个组件的动画,React Native内置的LayoutAnimation可以一键让所有布局变化自动带上过渡效果,代码极简。
修改后的代码示例
Home.js:
import React, { useState } from 'react'; import { View, Text, TouchableOpacity, LayoutAnimation, UIManager, Platform } from 'react-native'; import Tasks from './Tasks'; // Android需要手动开启布局动画实验特性 if (Platform.OS === 'android') { if (UIManager.setLayoutAnimationEnabledExperimental) { UIManager.setLayoutAnimationEnabledExperimental(true); } } export default function Home() { const [showmore, setShowmore] = useState(false); const toggleShowMore = () => { // 配置过渡动画,可选预设或自定义 LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); setShowmore(!showmore); }; return ( <View> <View> <Text>Render Something </Text> </View> {/* 正常条件渲染即可,LayoutAnimation会自动处理过渡 */} {showmore && <Tasks />} <TouchableOpacity onPress={toggleShowMore}> <Text>{showmore ? '收起' : '展开'} Button</Text> </TouchableOpacity> </View> ); }
方案对比
- Animated方案:灵活度高,可自定义动画曲线、时长,甚至添加其他过渡效果;缺点是代码量稍大。
- LayoutAnimation方案:代码极简,自动处理所有布局变化的动画;缺点是自定义程度低,Android需要额外配置。
内容的提问来源于stack exchange,提问作者abic17
相关产品推荐
相关产品推荐

