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

React Native中如何让TextInput悬浮在键盘上方?

问题:TextInput获取焦点时无法悬浮在键盘上方

我想要实现TextInput获取焦点时悬浮在键盘上方,但当前用Keyboard监听的方式存在e.endCoordinates.height数值偏差,导致输入框被键盘部分或完全遮挡,也没找到适配现有布局的KeyboardAvoidingView用法。

解决方案

1. 修复Keyboard监听错误

原代码中keyboardDidHideListener未绑定事件,会导致卸载时报错,需补充绑定keyboardDidHide事件,同时可按需保留键盘高度监听逻辑。

2. 改用KeyboardAvoidingView适配布局

无需手动计算键盘高度,用KeyboardAvoidingView包裹输入区域,结合平台差异设置behavior属性(iOS用padding,Android用height),配合ScrollView确保内容可滚动,避免布局挤压。

3. 简化输入框定位逻辑

移除手动设置position: absolute和bottom: keyboardHeight的复杂逻辑,交给原生组件自动处理布局,解决设备适配偏差问题。


修改后的SignUpScreen代码

import { useNavigation } from "@react-navigation/native";
import React, { useState, useEffect, useRef } from "react";
import {
  ImageBackground,
  Keyboard,
  StyleSheet,
  Text,
  View,
  useWindowDimensions,
  KeyboardAvoidingView,
  ScrollView,
  Platform
} from "react-native";

import { COLORS } from "../../assets/Colors/Colors";

import CustomButton from "../../components/CustomButton";
import CustomInput from "../../components/CustomInput";
import SocialSignInButtons from "../../components/SocialSignInButtons";

const SignUpScreen = () => {
  const [username, setUsername] = useState("");
  const [email, setEmail] = useState("");
  const window = useWindowDimensions();
  const navigation = useNavigation();
  const textInput1 = useRef();

  useEffect(() => {
    setTimeout(() => {
      textInput1.current?.focus();
    }, 0);
    
    // 修复键盘隐藏监听
    const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
      // 按需添加键盘隐藏后的逻辑
    });

    const keyboardDidShowListener = Keyboard.addListener(
      "keyboardDidShow",
      (e) => {
        // 若仍需获取键盘高度可保留此逻辑,否则可移除
        // setKeyboardHeight(e.endCoordinates.height);
      }
    );

    return () => {
      keyboardDidHideListener.remove();
      keyboardDidShowListener.remove();
    };
  }, []);

  const onRegisterPressed = () => {
    navigation.navigate("SignUp2");
  };

  const onSignInPressed = () => {
    navigation.navigate("SignIn");
  };

  const handleChange = (e, type) => {
    eval(`set${type}`)(e);
  };

  return (
    <ImageBackground
      resizeMode="stretch"
      source={require("../../assets/AppCustomBackgroundsFrench/SignUpFR.png")}
      style={styles.imageBackground}
    >
      <ScrollView
        contentContainerStyle={styles.scrollContent}
        keyboardShouldPersistTaps="handled"
        showsVerticalScrollIndicator={false}
      >
        <Text style={styles.title}>S'inscrire</Text>
        
        {/* 用KeyboardAvoidingView包裹输入区域 */}
        <KeyboardAvoidingView
          style={styles.inputContainer}
          behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
          keyboardVerticalOffset={Platform.OS === 'ios' ? 60 : 0} // 根据实际布局调整偏移量
        >
          <CustomInput
            ref={textInput1}
            onChangeText={(e) => handleChange(e, "Username")}
            placeholder="Username"
            value={username}
          />
          <CustomInput
            onChangeText={(e) => handleChange(e, "Email")}
            placeholder="Email"
            value={email}
          />
        </KeyboardAvoidingView>

        <CustomButton
          text="Suivant"
          onPress={onRegisterPressed}
          type="PRIMARY"
        />

        <SocialSignInButtons />

        <CustomButton
          text="Have an account? Sign In"
          onPress={onSignInPressed}
          type="TERTIARY"
        />
      </ScrollView>
    </ImageBackground>
  );
};

const styles = StyleSheet.create({
  imageBackground: {
    flex: 1,
    width: '100%',
    height: '100%',
  },
  scrollContent: {
    flexGrow: 1,
    alignItems: "center",
    paddingTop: window.height * 0.34,
    paddingBottom: 20,
    paddingHorizontal: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: "bold",
    color: "#360d59",
    marginBottom: 30,
    alignSelf: 'flex-start',
  },
  inputContainer: {
    width: '100%',
    alignItems: 'center',
    marginBottom: 40,
  },
});

export default SignUpScreen;

修改后的CustomInput代码

import { View, Text, TextInput, StyleSheet, Platform } from "react-native";
import React, { forwardRef, useState } from "react";
import { COLORS } from "../../assets/Colors/Colors";

const CustomInput = forwardRef(
  (
    { onFocus = () => {}, onBlur = () => {}, label, style, ...props },
    ref
  ) => {
    const [isOnFocus, setIsOnFocus] = useState(false);

    return (
      <View style={[{ width: "100%" }, style]}>
        {label && <Text style={styles.subtitle}>{label}</Text>}
        <View
          style={[
            styles.container,
            { borderColor: isOnFocus ? "yellow" : COLORS.input_Border_Violet },
          ]}
        >
          <TextInput
            ref={ref}
            autocorrect={false}
            style={styles.input}
            {...props}
            onFocus={() => {
              onFocus();
              setIsOnFocus(true);
            }}
            onBlur={() => {
              onBlur();
              setIsOnFocus(false);
            }}
          />
        </View>
      </View>
    );
  }
);

const styles = StyleSheet.create({
  container: {
    backgroundColor: "white",
    width: "80%",
    borderRadius: 15,
    borderWidth: 2,
    marginVertical: 10,
  },
  input: {
    paddingHorizontal: 10,
    paddingVertical: Platform.OS === 'ios' ? 15 : 12,
  },
  subtitle: {
    color: COLORS.background,
    fontSize: 16,
    fontWeight: "bold",
    alignSelf: 'flex-start',
    paddingLeft: '10%',
  },
});

export default CustomInput;

关键说明

  • KeyboardAvoidingView:根据平台自动调整布局方式,keyboardVerticalOffset可根据导航栏、安全区域高度微调,确保输入框不被遮挡。
  • ScrollView:包裹所有内容,键盘弹出时内容可滚动,避免底部按钮被挤压;keyboardShouldPersistTaps="handled"允许点击输入框外区域时保持键盘打开(按需调整)。
  • 移除手动定位:放弃监听键盘高度设置绝对定位的方式,依赖原生组件自动适配不同设备的键盘高度,解决数值偏差问题。

内容的提问来源于stack exchange,提问作者Rémi-Antoine Joron

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 20:42:10