Floating input in React Native

30 Views Asked by At

I'm trying to create a floating input in React Native, but the problem is that I have to press in the empty area (the red area) so that the placeholder could float and allow me to write inside the input field.

However, if I try to press the placeholder title, nothing happens. The placeholder doesn't float, the cursor doesn't appear, and I can't write.

enter image description here

this is my code


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,
    }
});
1

There are 1 best solutions below

0
Samyak Agrawal On BEST ANSWER

Try this

Wrap your Animated.View in Pressable and use onFocusHandler function on onPress

     <View style={styles.container}>
        <Pressable onPress={onFocusHandler}>
             <Animated.View style={[styles.animatedStyle, animStyle]}>
                 <Text style={styles.label}>{placeholder}</Text>
             </Animated.View>
        </Pressable>
        <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>