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

React Native中TextInput在键盘弹出过程中失焦的问题解决求助

React Native中TextInput在键盘弹出过程中失焦的问题解决求助

大家好,我最近在开发React Native项目时碰到了一个挺棘手的TextInput焦点问题,想请各位大佬帮忙支支招。

我的场景是:在一个可滚动的页面里有若干输入框,之前遇到点击输入框获取焦点后,滚动页面会触发onBlur导致输入框失焦,但键盘还保持打开状态,而且键盘类型会变回default的问题。后来我通过在滚动时收起键盘的方式解决了一部分,但现在还有个相关的问题没搞定:

当输入框位置比较靠下,我点击它的时候,页面会自动滚动把输入框移到可视区域,但紧接着这个输入框就触发了onBlur失焦了,键盘依然保持打开状态,却没有任何输入框获得焦点。我猜测可能是键盘弹出的瞬间,输入框被键盘短暂遮挡导致暂时不可见,这时候React Native就判定它失去了焦点,等页面滚动调整位置让输入框回到可视区域时,它已经失焦了。

下面是我的相关代码:

自定义TextInput组件代码

({
  disabled = false,
  error = false,
  errorMessage,
  icon,
  iconPressed,
  inputId,
  isTextArea = false,
  label,
  maskType = "custom",
  onchangeText,
  onPressIcon,
  placeholder,
  required = false,
  styleInput,
  styleView,
  type = "string",
  variant = "default",
  width = "100%",
  infoToShow = "",
  ...props
}: InputProps,
ref: Ref<TextInput | TextInputMask>,
//Passar Ref<TextInput> caso o campo não necessite de máscara. Caso precise, passar Ref<TextInputMask>
) => {
  const [focused, setFocused] = useState(false);
  const isDefaultSize = !isTextArea;
  const showIconPressed = false && iconPressed !== undefined;
  let options: TextInputMaskOptionProp;

  switch (maskType) {
    case "credit-card":
      options = {
        obfuscated: false,
        issuer: "visa-or-mastercard",
      };
      break;
    case "money":
      options = {
        unit: "R$",
      };
      break;
    case "cel-phone":
      options = {
        maskType: "BRL",
        withDDD: true,
        dddMask: "(99) ",
      };
      break;
    case "datetime":
      options = { format: "DD/MM/YYYY" };
  }

  const borderStyle = [
    variant === "default"
      ? { borderWidth: 1, borderRadius: 8, }
      : { borderBottomWidth: 1, },
    {
      borderColor: error
        ? Colors.v4RedError
        : disabled
        ? Colors.v7GrayDisabled
        : focused && variant === "bottom-line"
        ? Colors.primary
        : Colors.v3GraySubtitle,
    },
  ] as StyleProp<ViewStyle>;

  useEffect(() => {
    if (!focused) {
      hideKeyboard();
    }
  }, [focused])

  function textInputByMask() {
    if (maskType === "custom") {
      return (
        <TextInput
          {...props}
          ref={ref as Ref<TextInput>}
          placeholder={placeholder}
          cursorColor={Colors.primary}
          numberOfLines={isDefaultSize ? 1 : 7}
          multiline={!isDefaultSize}
          textAlignVertical={isDefaultSize ? "center" : "top"}
          placeholderTextColor={Colors.v2GrayLargeText}
          editable={!disabled}
          onFocus={val => {
            setFocused(true);
          }}
          onBlur={() => {
            setFocused(false);
          }}
          style={[
            globalStyles.textBody2,
            styleInput,
            { color: Colors.v2GrayLargeText, flex: 1, textAlign: "left" },
          ]}
        />
      );
    }
    return (
      <TextInputMask
        ref={ref as Ref<TextInputMask>}
        {...props}
        keyboardType="number-pad"
        placeholder={placeholder}
        options={options}
        cursorColor={Colors.primary}
        numberOfLines={isDefaultSize ? 1 : 7}
        multiline={!isDefaultSize}
        textAlignVertical={isDefaultSize ? "center" : "top"}
        placeholderTextColor={Colors.v2GrayLargeText}
        editable={!disabled}
        type={maskType}
        onFocus={val => {
          setFocused(true);
        }}
        onBlur={() => { setFocused(false) }}
        style={[
          globalStyles.textBody2,
          styleInput,
          { color: Colors.v2GrayLargeText, flex: 1, textAlign: "left" },
        ]}
      />
    );
  }

  return (
    <View style={{ gap: 5 }}>
      <LabelRequired
        label={label}
        color={error ? "v4RedError" : "v1GrayTitle"}
        required={required}
        infoToShow={infoToShow}
      />
      <View style={[
        allStyles.searchBarContainer,
        styleView,
        borderStyle,
        {
          width,
          backgroundColor: disabled ? Colors.v5GrayDivider : Colors.transparent,
        },
      ]}>
        {textInputByMask()}
        {icon && (
          <TouchableOpacity
            activeOpacity={onPressIcon ? undefined : 1}
            onPress={() => {
              if (onPressIcon) {
                onPressIcon();
              }
            }}>
            <IconStyled
              icon={showIconPressed ? iconPressed.icon : icon.icon}
              color={error ? "v4RedError" : icon.color}
              size={icon.size}
            />
          </TouchableOpacity>
        )}
      </View>
      {errorMessage && (
        <Subtitle
          variant="subtitle3"
          color={error ? "v4RedError" : "v3GraySubtitle"}
          fontWeight="NotoSans Regular"
          leftText>
          {errorMessage}
        </Subtitle>
      )}
    </View>
  );
},

渲染输入列表的组件代码

export default function EtapaExecucao({ etapa }: EtapaExecucaoProps) {
  const itensOrdenados = [...etapa.etapaItens].sort((a, b) => a.ordem - b.ordem);
  // 注:原代码未完整提供,此处仅展示已有的部分

我现在的需求是找到一个能彻底解决这个问题的方案,让输入框在键盘弹出的整个过程中都不会失去焦点,请问各位有没有什么可行的办法或者思路?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 11:14:52