React Native浮动输入框问题:点击占位符无法激活输入
React Native浮动输入框点击占位符无响应问题
开发React Native浮动输入框时遇到问题:点击输入框空白区域(红色区域),占位符会上浮并允许输入;但点击占位符文本时,完全没反应,占位符不上浮、没有光标,无法输入。
问题代码
export default function SingleLineText({ onChange, placeholder, columnName, requiredInput, inputValue }) { const [value, setValue] = useState(""); const moveText = useRef(new Animated.Value(0)).current; const schema = yup.object().shape({ columnName: yup.string().required('You should enter this field.'), }); const { control, handleSubmit, formState: { errors } } = useForm({ resolver: yupResolver(schema), defaultValues: { columnName: inputValue ? inputValue : '', }, }); useEffect(() => { if (value !== "") { moveTextTop(); } else if (value === "") { moveTextBottom(); } }, [value]) useEffect(() => { onChange(value) }, [value]) const onChangeText = (text) => { setValue(text); }; const onFocusHandler = () => { moveTextTop(); }; const onBlurHandler = () => { if (value === "") { moveTextBottom(); } }; const moveTextTop = () => { Animated.timing(moveText, { toValue: 1, duration: 200, useNativeDriver: true, }).start(); }; const moveTextBottom = () => { Animated.timing(moveText, { toValue: 0, duration: 200, useNativeDriver: true, }).start(); }; const yVal = moveText.interpolate({ inputRange: [0, 2.5], outputRange: [4, -20], }); const animStyle = { transform: [ { translateY: yVal, }, ], }; return ( <View style={styles.container}> <Animated.View style={[styles.animatedStyle, animStyle]}> <Text style={styles.label}>{placeholder}</Text> </Animated.View> <Controller control={control} rules={{ requiredInput }} render={({ field: { onChange, value, onBlur } }) => ( <TextInput onBlur={onBlurHandler} value={inputValue} onChangeText={onChangeText} style={styles.input} onFocus={onFocusHandler} /> )} name={columnName} /> {errors.columnName && <Text >{errors?.columnName?.message}</Text>} </View> ) } const styles = StyleSheet.create({ container: { height: 53, backgroundColor: Colors.lightGray, borderRadius: 8, paddingTop: 15, marginVertical: 5, paddingHorizontal: 18, borderColor: "#bdbdbd", width: "100%", justifyContent: "center", }, input: { fontFamily: FONTS.PoppinsRegular, fontSize: 18, height: 53, }, label: { paddingVertical: 5, fontFamily: FONTS.PoppinsRegular, color: Colors.SmokeBlue, fontSize: 15, }, animatedStyle: { top: 4, left: 15, position: 'absolute', borderRadius: 90, zIndex: 10000, }, errorMessage: { color: Colors.Red, fontFamily: FONTS.PoppinsMedium, fontSize: 10, } });
问题根源
占位符的Animated.View设置了zIndex: 10000,层级远高于下方的TextInput,导致点击占位符文本时,实际触发的是占位符容器的点击事件,而非输入框,因此无法触发输入框聚焦和占位符上浮动画。
修复方案
1. 调整层级关系
降低占位符容器的zIndex,让TextInput能接收点击事件:
// 修改styles中的animatedStyle animatedStyle: { top: 4, left: 15, position: 'absolute', borderRadius: 90, zIndex: 1, // 从10000改为1 },
或者给TextInput添加更高的zIndex:
// 修改styles中的input input: { fontFamily: FONTS.PoppinsRegular, fontSize: 18, height: 53, zIndex: 2, },
2. 统一表单状态管理
当前代码同时使用本地useState和react-hook-form状态,容易导致数据不一致。建议直接使用react-hook-form的状态驱动输入和动画:
export default function SingleLineText({ onChange, placeholder, columnName, requiredInput, inputValue }) { const moveText = useRef(new Animated.Value(0)).current; const schema = yup.object().shape({ columnName: yup.string().required('You should enter this field.'), }); const { control, handleSubmit, formState: { errors }, watch } = useForm({ resolver: yupResolver(schema), defaultValues: { columnName: inputValue ? inputValue : '', }, }); // 监听表单值变化,驱动动画 useEffect(() => { const currentValue = watch(columnName); if (currentValue) { moveTextTop(); } else { moveTextBottom(); } onChange(currentValue); // 同步父组件状态 }, [watch(columnName), onChange]) const moveTextTop = () => { Animated.timing(moveText, { toValue: 1, duration: 200, useNativeDriver: true, }).start(); }; const moveTextBottom = () => { Animated.timing(moveText, { toValue: 0, duration: 200, useNativeDriver: true, }).start(); }; const yVal = moveText.interpolate({ inputRange: [0, 2.5], outputRange: [4, -20], }); const animStyle = { transform: [ { translateY: yVal, }, ], }; return ( <View style={styles.container}> <Animated.View style={[styles.animatedStyle, animStyle]}> <Text style={styles.label}>{placeholder}</Text> </Animated.View> <Controller control={control} rules={{ requiredInput }} render={({ field: { onChange: fieldOnChange, value, onBlur } }) => ( <TextInput onBlur={() => { onBlur(); if (!value) moveTextBottom(); }} value={value} onChangeText={fieldOnChange} style={styles.input} onFocus={moveTextTop} /> )} name={columnName} /> {errors.columnName && <Text style={styles.errorMessage}>{errors.columnName.message}</Text>} </View> ) }
3. 可选:占位符点击触发聚焦
如果需要点击占位符文本也能激活输入框,给占位符添加点击事件并绑定输入框ref:
// 组件内添加inputRef const inputRef = useRef(null); // 修改占位符Text组件 <Text style={styles.label} onPress={() => inputRef.current?.focus()}>{placeholder}</Text> // 给TextInput绑定ref <TextInput ref={inputRef} // 其他属性... />
内容的提问来源于stack exchange,提问作者med hedi ben salah
相关产品推荐
相关产品推荐

