如何使用React Native Reanimated实现TextInput聚焦展开动画?
用React Native Reanimated实现TextInput聚焦展开动画
问题说明
我正在学习React Native,想要实现一个聚焦时展开的TextInput动画效果。目前我通过useState和样式切换实现了该功能,但需要改用React Native Reanimated来完成。
初始状态:
聚焦目标状态:
解决方案
首先确保已安装React Native Reanimated:
npm install react-native-reanimated # 或 yarn add react-native-reanimated
修改组件代码,用Reanimated的共享值和动画函数替代useState:
import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing, } from 'react-native-reanimated'; import { TextInput, View } from 'react-native'; const inputRef = useRef<TextInput>(); // 用共享值替代useState,控制动画进度 const isFocused = useSharedValue(false); // 处理失焦 const handleBlurInput = () => { inputRef.current?.blur(); isFocused.value = false; }; // 处理聚焦 const handleFocusInput = () => { inputRef.current?.focus(); isFocused.value = true; }; const Footer = () => { // 输入框的动画样式 const inputAnimatedStyle = useAnimatedStyle(() => { return { minWidth: withTiming( isFocused.value ? 295 : 134, { duration: 300, easing: Easing.inOut(Easing.ease) } ), height: withTiming( isFocused.value ? 50 : 'auto', { duration: 300, easing: Easing.inOut(Easing.ease) } ), marginRight: withTiming( isFocused.value ? 60 : 0, { duration: 300, easing: Easing.inOut(Easing.ease) } ), }; }); // 按钮的显隐动画 const buttonsAnimatedStyle = useAnimatedStyle(() => { return { opacity: withTiming( isFocused.value ? 0 : 1, { duration: 200 } ), width: withTiming( isFocused.value ? 0 : 'auto', { duration: 200 } ), marginRight: withTiming( isFocused.value ? 0 : 10, { duration: 200 } ), }; }); // 聚焦图标的显隐动画 const iconAnimatedStyle = useAnimatedStyle(() => { return { opacity: withTiming( isFocused.value ? 1 : 0, { duration: 200 } ), }; }); return ( <View style={styles.footer}> {/* 初始状态的两个按钮,带动画隐藏 */} <Animated.View style={buttonsAnimatedStyle}> <Button text="Button1" onPress={onButton1} buttonStyle={styles.button} /> </Animated.View> <Animated.View style={buttonsAnimatedStyle}> <Button text="Button2" onPress={onButton2} buttonStyle={styles.button} /> </Animated.View> {/* 聚焦时显示的图标,带动画显示 */} <Animated.View style={iconAnimatedStyle}> {isFocused.value && ( <IconView name="ChevronRightLight" onPress={handleBlurInput} style={styles.iconView} /> )} </Animated.View> <View style={styles.messageContainer}> <Animated.View style={inputAnimatedStyle}> <TextInputField ref={inputRef} style={styles.messageInput} placeholder="Message..." onPressIn={handleFocusInput} onFocus={handleFocusInput} onBlur={handleBlurInput} autoFocus={isFocused.value} placeholderTextColor='white' /> </Animated.View> </View> </View> ); };
调整后的样式代码
移除原来的fullMessageInput,保留基础样式:
footer: { flexDirection: 'row', bottom: 0, alignItems: 'center', }, button: { paddingVertical: 8, paddingHorizontal: 8, }, messageContainer: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', }, messageInput: { borderWidth: 1, borderColor: 'grey', paddingLeft: 11, color: 'white', fontWeight: '500', fontSize: 14, lineHeight: 16, }, iconView: { /* 根据需要添加图标样式 */ },
关键说明
- 共享值
useSharedValue:替代useState存储聚焦状态,Reanimated可直接监听其变化驱动动画。 useAnimatedStyle:根据共享值生成动画样式,withTiming提供平滑过渡,支持自定义时长和缓动函数。- 动画包裹:需要动画的元素用
Animated.View包裹,确保样式变化被Reanimated处理。 - 平滑过渡:通过透明度、宽度的动画实现按钮和图标的显隐,避免直接条件渲染的突兀感。
内容的提问来源于stack exchange,提问作者Kumar Shivam
相关产品推荐
相关产品推荐

