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

React Native:react-native-phone-number-input无onFocus实现标签动画

问题:react-native-phone-number-input 组件无 onFocus 属性,无法触发标签动画

我用 react-native-phone-number-input 开发手机号输入功能,需要通过聚焦事件触发标签动画,但这个组件本身没有 onFocus 属性,目前无法实现需求。

我的组件代码:

const TestComponent = () => {
  const [value, setValue] = useState('')
  const [formattedValue, setFormattedValue] = useState('')
  const [valid, setValid] = useState(false)
  const [showMessage, setShowMessage] = useState(false)
  const phoneInput = useRef<PhoneInput>(null)
  const [isFocused, setIsFocused] = useState(true)

  const focusAnimation = useRef(new Animated.Value(0)).current

  const scale = focusAnimation.interpolate({
    inputRange: [0, 1],
    outputRange: [1, 0.75],
  })

  const translateY = focusAnimation.interpolate({
    inputRange: [0, 1],
    outputRange: [20, 0],
  })

  const translateX = focusAnimation.interpolate({
    inputRange: [0, 1],
    outputRange: [8, -150],
  })

  let borderColor = isFocused ? colors.primary : colors.gray600
  let labelColor = isFocused || value ? colors.primary : colors.gray400

  return (
    <View>
      {showMessage && (
        <View>
          <Text>Value : {value}</Text>
          <Text>Formatted Value : {formattedValue}</Text>
          <Text>Valid : {valid ? 'true' : 'false'}</Text>
        </View>
      )}
      <>
        <PhoneInput
          ref={phoneInput}
          defaultValue={value}
          defaultCode='TR'
          layout='first'
          onChangeText={text => {
            setValue(text)
          }}
          onChangeFormattedText={text => {
            setFormattedValue(text)
          }}
          placeholder='Telefon Numarası'
          containerStyle={styles.containerStyle}
          textContainerStyle={styles.textContainerStyle}
          textInputStyle={styles.textInputStyle}
          codeTextStyle={styles.codeTextStyle}
          flagButtonStyle={styles.flagButtonStyle}
          countryPickerButtonStyle={styles.countryPickerButtonStyle}
        />
      </>
    </View>
  )
}

当前效果:
当前手机号输入框效果

期望效果:
期望的带标签动画的手机号输入框效果


解决方案

可以通过以下两种方式实现聚焦事件监听,进而触发标签动画:

方法1:利用组件内部的 TextInput 引用

react-native-phone-number-input 内部包含原生 TextInput,可以通过组件的 ref 获取内部输入框引用,添加聚焦/失焦监听:

修改后的完整代码:

const TestComponent = () => {
  const [value, setValue] = useState('')
  const [formattedValue, setFormattedValue] = useState('')
  const [valid, setValid] = useState(false)
  const [showMessage, setShowMessage] = useState(false)
  const phoneInput = useRef<PhoneInput>(null)
  const [isFocused, setIsFocused] = useState(false)

  const focusAnimation = useRef(new Animated.Value(0)).current

  const scale = focusAnimation.interpolate({
    inputRange: [0, 1],
    outputRange: [1, 0.75],
  })

  const translateY = focusAnimation.interpolate({
    inputRange: [0, 1],
    outputRange: [20, 0],
  })

  const translateX = focusAnimation.interpolate({
    inputRange: [0, 1],
    outputRange: [8, -150],
  })

  let borderColor = isFocused ? colors.primary : colors.gray600
  let labelColor = isFocused || value ? colors.primary : colors.gray400

  useEffect(() => {
    if (phoneInput.current) {
      const textInputRef = phoneInput.current.textInputRef;
      if (textInputRef) {
        // 监听聚焦事件
        const focusListener = textInputRef.addListener('focus', () => {
          setIsFocused(true);
          Animated.timing(focusAnimation, {
            toValue: 1,
            duration: 200,
            useNativeDriver: false,
          }).start();
        });
        // 监听失焦事件
        const blurListener = textInputRef.addListener('blur', () => {
          if (!value) {
            setIsFocused(false);
            Animated.timing(focusAnimation, {
              toValue: 0,
              duration: 200,
              useNativeDriver: false,
            }).start();
          }
        });
        // 清理监听
        return () => {
          focusListener.remove();
          blurListener.remove();
        };
      }
    }
  }, [value, focusAnimation]);

  return (
    <View style={{ position: 'relative' }}>
      {/* 自定义动画标签 */}
      <Animated.Text
        style={{
          position: 'absolute',
          left: 8,
          top: 0,
          transform: [{ scale }, { translateY }, { translateX }],
          color: labelColor,
          fontSize: 12,
        }}
      >
        Telefon Numarası
      </Animated.Text>
      {showMessage && (
        <View>
          <Text>Value : {value}</Text>
          <Text>Formatted Value : {formattedValue}</Text>
          <Text>Valid : {valid ? 'true' : 'false'}</Text>
        </View>
      )}
      <PhoneInput
        ref={phoneInput}
        defaultValue={value}
        defaultCode='TR'
        layout='first'
        onChangeText={text => {
          setValue(text);
          // 输入内容时触发动画
          if (!isFocused) {
            setIsFocused(true);
            Animated.timing(focusAnimation, {
              toValue: 1,
              duration: 200,
              useNativeDriver: false,
            }).start();
          }
        }}
        onChangeFormattedText={text => {
          setFormattedValue(text)
        }}
        placeholder=''
        containerStyle={[styles.containerStyle, { borderColor, paddingTop: 16 }]}
        textContainerStyle={styles.textContainerStyle}
        textInputStyle={styles.textInputStyle}
        codeTextStyle={styles.codeTextStyle}
        flagButtonStyle={styles.flagButtonStyle}
        countryPickerButtonStyle={styles.countryPickerButtonStyle}
      />
    </View>
  )
}

方法2:包装组件监听触摸事件

如果无法获取内部引用,可给 PhoneInput 外层套 TouchableWithoutFeedback,通过触摸事件模拟聚焦触发(注意:点击国家选择器也会触发此事件):

<TouchableWithoutFeedback onPress={() => {
  phoneInput.current?.focus();
  setIsFocused(true);
  Animated.timing(focusAnimation, {
    toValue: 1,
    duration: 200,
    useNativeDriver: false,
  }).start();
}}>
  <PhoneInput
    // ...其他属性
  />
</TouchableWithoutFeedback>

关键修改说明:

  • 移除原组件占位符,改用自定义动画标签
  • 通过内部 textInputRef 监听 focus/blur 事件,精准触发动画
  • 输入内容时同步触发动画,确保输入后标签保持上浮状态
  • 调整输入框容器内边距,避免标签与输入内容重叠

内容的提问来源于stack exchange,提问作者the Great A

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 16:00:59