通过工具栏按钮收起键盘后,多行文本输入框再次获得焦点
在我的React Native(Expo)应用中,当使用自定义工具栏按钮来隐藏键盘时,遇到了一个奇怪的键盘焦点问题。
如果通过硬件 Esc 键关闭键盘,TextInput 会完全失去焦点。之后,我可以滚动内容,松开手指时,键盘仍然保持开启状态(如预期)。
如果我点击自定义工具栏按钮,它会调用 Keyboard.dismiss(),键盘会隐藏,但 TextInput 仍然保持焦点状态。由于焦点仍然处于活动状态,滚动内容并松手后,键盘会立刻弹回。
下面是按上下文块分隔的函数组件代码,以符合格式规则:
首先,核心组件逻辑和钩子配置:
import { MaterialIcons } from "@expo/vector-icons";
import { useHeaderHeight } from "expo-router/react-navigation";
import { useEffect, useState } from "react";
import {
Keyboard,
KeyboardAvoidingView,
Platform,
Pressable,
StyleSheet,
TextInput,
View,
} from "react-native";
export default function WriteScreen() {
const headerHeight = useHeaderHeight();
const [isKeyboardVisible, setIsKeyboardVisible] = useState(false);
接下来,跟踪软键盘可见性状态的事件监听:
useEffect(() => {
const showEvent =
Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow";
const hideEvent =
Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide";
const show = Keyboard.addListener(showEvent, () =>
setIsKeyboardVisible(true),
);
const hide = Keyboard.addListener(hideEvent, () =>
setIsKeyboardVisible(false),
);
return () => {
show.remove();
hide.remove();
};
}, []);
const dismissKeyboard = () => {
Keyboard.dismiss();
};
以下是包含 KeyboardAvoidingView 包装器和多行输入的UI布局结构:
return (
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS === "ios" ? "padding" : "height"}
keyboardVerticalOffset={headerHeight}
>
<TextInput
style={styles.title}
placeholder="제목"
placeholderTextColor="#999"
/>
<TextInput
style={styles.content}
placeholder="내용"
placeholderTextColor="#999"
multiline
textAlignVertical="top"
/>
最后,包含条件关闭按钮的工具栏布局:
<View style={styles.toolbar}>
{isKeyboardVisible ? (
<Pressable
style={styles.keyboardDismissButton}
onPress={dismissKeyboard}
hitSlop={8}
accessibilityRole="button"
>
<MaterialIcons name="keyboard-hide" size={22} />
</Pressable>
) : null}
</View>
</KeyboardAvoidingView>
);
}
下面是完整的样式表:
const styles = StyleSheet.create({
container: {
flex: 1,
paddingHorizontal: 16,
backgroundColor: "#fff",
},
flex: {
flex: 1,
},
scrollContent: {
flexGrow: 1,
},
title: {
fontSize: 20,
fontWeight: "bold",
paddingVertical: 12,
},
content: {
flexGrow: 1,
fontSize: 16,
textAlignVertical: "top",
},
toolbar: {
height: 48,
flexDirection: "row",
justifyContent: "flex-end",
alignItems: "center",
borderTopWidth: StyleSheet.hairlineWidth,
borderTopColor: "#ddd",
},
toolbarButton: {
padding: 8,
},
keyboardDismissButton: {
padding: 4,
borderRadius: 10,
alignItems: "center",
justifyContent: "center",
},
});
如何让自定义工具栏按钮彻底终止/让 TextInput 的焦点生命周期像 Esc 键一样被移除,以便之后滚动不会再次意外触发键盘?
解决方案
问题在于 Keyboard.dismiss() 会在视觉上隐藏键盘,但不会让当前聚焦的 TextInput 失去焦点,因此它仍然保持焦点,在滚动结束时会重新触发键盘。
修复方式是显式地让当前聚焦的输入失去焦点:
const dismissKeyboard = () => {
const currentInput = TextInput.State.currentlyFocusedInput();
if (currentInput) {
currentInput.blur();
}
Keyboard.dismiss();
};
TextInput.State.currentlyFocusedInput() 返回当前活动输入的原生引用,对它调用 .blur(),就能实现与原生Esc键相同的效果。Keyboard.dismiss() 作为Android端边缘情况的安全网保留。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。