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

React Native Android软键盘顶起视图 自定义底部弹窗搜索适配问题

解决方案

第一步:修正AndroidManifest配置

只保留android:windowSoftInputMode="adjustResize",不要同时配置adjustPan,RN官方明确说明二者混用会导致键盘事件监听器失效,这是之前监听器不工作的直接原因。

第二步:替换固定屏幕高度获取方式

不要用Dimensions.get('screen')获取固定高度,安卓下adjustResize模式弹出键盘时,屏幕总高度不变,仅窗口可用高度变化,改用RN提供的useWindowDimensions钩子实时获取窗口高度,自动响应键盘弹出后的高度变化。

第三步:重构动画定位逻辑

之前同时给绝对定位的组件设置top和bottom属性,二者在安卓窗口高度变化时会产生冲突,改为仅固定底部,用translateY控制弹窗位置,完全避开窗口高度变化带来的定位异常:

  1. 初始状态弹窗完全隐藏在屏幕顶部,设置translateY: -窗口高度
  2. 中部停靠时translateY设为对应需要的停靠偏移值
  3. 底部停靠时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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 15:39:01