React Native Android软键盘顶起视图 自定义底部弹窗搜索适配问题
解决方案
第一步:修正AndroidManifest配置
只保留android:windowSoftInputMode="adjustResize",不要同时配置adjustPan,RN官方明确说明二者混用会导致键盘事件监听器失效,这是之前监听器不工作的直接原因。
第二步:替换固定屏幕高度获取方式
不要用Dimensions.get('screen')获取固定高度,安卓下adjustResize模式弹出键盘时,屏幕总高度不变,仅窗口可用高度变化,改用RN提供的useWindowDimensions钩子实时获取窗口高度,自动响应键盘弹出后的高度变化。
第三步:重构动画定位逻辑
之前同时给绝对定位的组件设置top和bottom属性,二者在安卓窗口高度变化时会产生冲突,改为仅固定底部,用translateY控制弹窗位置,完全避开窗口高度变化带来的定位异常:
- 初始状态弹窗完全隐藏在屏幕顶部,设置
translateY: -窗口高度 - 中部停靠时
translateY设为对应需要的停靠偏移值 - 底部停靠时
translateY设为0
第四步:修正键盘事件监听写法
当前的键盘监听没有添加清理逻辑,多次进入页面会触发重复监听,把监听逻辑放到useEffect中,返回卸载函数:
useEffect(() => { const keyboardDidShowListener = Keyboard.addListener("keyboardDidShow", () => { if (bottomSheetState === "bottom") { contentTranslateY.value = withSpring( -windowHeight / 2 // 对应中部停靠位置 ); } }); return () => { keyboardDidShowListener.remove(); }; }, [bottomSheetState, windowHeight]);
第五步:适配安卓状态栏/导航栏高度
安卓下计算偏移时要减去StatusBar.currentHeight的状态栏高度,避免出现偏移错位。
修正后的ScrollBottomSheet核心代码示例
import { useWindowDimensions, StatusBar } from 'react-native'; const ScrollBottomSheet = ({ children }: Props) => { const { height: WINDOW_HEIGHT } = useWindowDimensions(); const REAL_WINDOW_HEIGHT = Platform.OS === 'android' ? WINDOW_HEIGHT - (StatusBar.currentHeight || 0) : WINDOW_HEIGHT; // 停靠点配置:初始全隐藏、中部停靠、底部停靠 const SNAP_POINTS = { TOP: -REAL_WINDOW_HEIGHT, MIDDLE: -REAL_WINDOW_HEIGHT / 2, BOTTOM: 0 }; const contentTranslateY = useSharedValue(SNAP_POINTS.TOP); const [bottomSheetState, setBottomSheetState] = useState("top"); useEffect(() => { const showListener = Keyboard.addListener("keyboardDidShow", () => { if (bottomSheetState === "bottom") { contentTranslateY.value = withSpring(SNAP_POINTS.MIDDLE); } }); return () => showListener.remove(); }, [bottomSheetState]); const animatedStyle = useAnimatedStyle(() => { "worklet"; return { transform: [{ translateY: contentTranslateY.value }] }; }); // 手势逻辑内对应修改contentTranslateY的赋值,替换原来的contentTop逻辑即可 // ...剩余手势逻辑保持结构不变,仅替换停靠点值为SNAP_POINTS内的配置 return ( <PanGestureHandler onGestureEvent={gestureHandler}> <Animated.View style={[styles.container, animatedStyle]}> <View style={styles.grbber} /> {children} </Animated.View> </PanGestureHandler> ); }; const styles = StyleSheet.create({ container: { position: "absolute", left: 0, right: 0, bottom: 0, // 仅固定底部,不设置top height: '100%', // 固定弹窗高度为窗口全高 backgroundColor: "#fff", shadowOffset: { height: -6, width: 0, }, shadowOpacity: 0.1, shadowRadius: 5, borderTopEndRadius: 15, borderTopLeftRadius: 15, }, // 其余样式保持不变 });
修改后安卓下adjustResize模式的键盘事件可以正常监听,弹窗位置完全由translateY控制,不会被系统自动顶上去,也不会被键盘遮挡,和iOS逻辑保持一致。
内容的提问来源于stack exchange,提问作者user12494839
相关产品推荐
相关产品推荐

