You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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: {
  /* 根据需要添加图标样式 */
},

关键说明

  1. 共享值useSharedValue:替代useState存储聚焦状态,Reanimated可直接监听其变化驱动动画。
  2. useAnimatedStyle:根据共享值生成动画样式,withTiming提供平滑过渡,支持自定义时长和缓动函数。
  3. 动画包裹:需要动画的元素用Animated.View包裹,确保样式变化被Reanimated处理。
  4. 平滑过渡:通过透明度、宽度的动画实现按钮和图标的显隐,避免直接条件渲染的突兀感。

内容的提问来源于stack exchange,提问作者Kumar Shivam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 09:45:34