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

如何在React Native中实现点击后占位符移至顶部的文本输入组件

Hey there! I totally get what you're going for—this sleek UI pattern is called a floating label input, and it's super doable in React Native. Let me walk you through building it from scratch (no external libraries required, though I'll mention a shortcut too!)

How to Build a Floating Label Input in React Native

Core Idea

We'll create a custom component that tracks two key states:

  • Whether the input is focused
  • If there's text already entered in the input

Based on these states, we'll animate a label (our "placeholder") from the center of the input up to the top, shrinking its font size and adjusting its color along the way. React Native's Animated API will handle the smooth transition.

Full Component Code

import React, { useState, useRef, useEffect } from 'react';
import { View, TextInput, Animated, StyleSheet } from 'react-native';

const FloatingLabelInput = ({ label, value, onChangeText, ...props }) => {
  const [isFocused, setIsFocused] = useState(false);
  const inputValueRef = useRef(value || '');
  const labelAnimation = useRef(new Animated.Value(0)).current;

  // Update ref when external value changes
  useEffect(() => {
    inputValueRef.current = value || '';
    // Trigger animation immediately if value exists on mount
    if (inputValueRef.current) {
      Animated.timing(labelAnimation, {
        toValue: 1,
        duration: 200,
        useNativeDriver: false,
      }).start();
    }
  }, [value]);

  // Handle focus and animate label up
  const handleFocus = () => {
    setIsFocused(true);
    Animated.timing(labelAnimation, {
      toValue: 1,
      duration: 200,
      useNativeDriver: false,
    }).start();
  };

  // Handle blur: keep label up if input has content, else reset it
  const handleBlur = () => {
    const hasContent = inputValueRef.current !== '';
    setIsFocused(hasContent);
    Animated.timing(labelAnimation, {
      toValue: hasContent ? 1 : 0,
      duration: 200,
      useNativeDriver: false,
    }).start();
  };

  // Map animation values to label styles
  const labelStyle = {
    transform: [
      {
        translateY: labelAnimation.interpolate({
          inputRange: [0, 1],
          outputRange: [15, -12], // Move from center to top
        }),
      },
    ],
    fontSize: labelAnimation.interpolate({
      inputRange: [0, 1],
      outputRange: [16, 12], // Shrink font size
    }),
    color: labelAnimation.interpolate({
      inputRange: [0, 1],
      outputRange: ['#999', '#2196F3'], // Darken color when active
    }),
  };

  return (
    <View style={styles.container}>
      <Animated.Text style={[styles.label, labelStyle]}>
        {label}
      </Animated.Text>
      <TextInput
        style={styles.input}
        value={value}
        onChangeText={(text) => {
          inputValueRef.current = text;
          onChangeText(text);
        }}
        onFocus={handleFocus}
        onBlur={handleBlur}
        {...props}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    position: 'relative',
    marginVertical: 16,
  },
  label: {
    position: 'absolute',
    left: 12,
    backgroundColor: '#fff', // Match your screen's background color
    paddingHorizontal: 4,
  },
  input: {
    height: 48,
    borderWidth: 1,
    borderColor: '#ccc',
    borderRadius: 8,
    paddingHorizontal: 12,
    paddingTop: 16, // Make space for the floating label
    fontSize: 16,
  },
});

export default FloatingLabelInput;

Breakdown of Key Parts

  • State & Refs: We use useState for focus state and useRef to track input content (so we can keep the label up even after the input loses focus if there's text inside).
  • Animation: Animated.timing drives smooth transitions, and interpolate maps our animation value (0 = inactive, 1 = active) to style changes like position, size, and color.
  • Input Padding: The paddingTop on the input ensures typed text doesn't overlap with the floating label when it's at the top.
  • Label Background: Setting a background color on the label makes it "cover" the input border when floating up—match this to your screen's background for a clean look.

Shortcut: Use a UI Library

If you don't want to build this from scratch, most React Native UI libraries include this component out of the box:

  • React Native Paper: Their TextInput has mode="outlined" or mode="flat" options that include floating labels by default.
  • NativeBase: The Input component supports floating labels via the variant="floating" prop.

内容的提问来源于stack exchange,提问作者MIike Eps

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 20:27:46