React Native 底部标签栏在打开键盘时向上推移

25
我们正在使用createBottomTabNavigator。其中一个选项卡包含顶部的搜索栏。点击该搜索栏时,会打开键盘。但是键盘也会将底部的选项卡推上去。我们需要在打开键盘时保持底部选项卡仍在底部。
我尝试过的解决方案之一是,在android manifest中更改android:windowSoftInputMode="adjustPan"或"adjustNothing"。这正常工作,但我们在另一个选项卡中使用聊天布局,需要"adjustResize"。因此,我必须保持windowSoftInputMode为"adjustResize"。
另一种解决方案是,在组件内部更改windowSoftInputMode。因此,我尝试了https://www.npmjs.com/package/react-native-android-keyboard-adjust,但没有用处。
还有一种方法是创建一个类似于https://github.com/react-navigation/react-navigation/issues/618中提到的TabBarComponent。但是效果不如预期。
const SignedIn = createBottomTabNavigator(
  {
    Followers: {
      screen: FollowerStack,
      ...
    },
    Search: {
      screen: SearchStack,
    },
    Home: {
      screen: HomeStack,
    },
    Bookmarks: {
      screen: BookmarkStack,
    },
    Profile: {
      screen: ProfileStack,
    }
  },
  {
    initialRouteName: "Home",
    tabBarPosition: 'bottom',
    swipeEnabled: false,
    animationEnabled: false,
    tabBarOptions: {
      keyboardHidesTabBar: true,
      showIcon: true,
      showLabel: false,
      activeTintColor: "red",
      inactiveTintColor: "gray",
      adaptive: true,
      safeAreaInset: {
        bottom: "always"
      },
      style: {
        position: 'relative',
        backgroundColor: "#F9F8FB",
        height: TAB_NAVIGATOR_DYNAMIC_HEIGHT,
        paddingTop: DeviceInfo.hasNotch() ? "5%" : "0%",
        minHeight: TAB_NAVIGATOR_DYNAMIC_HEIGHT,
        width: '100%',
        bottom: 0
      }
    }
  }
);
  1. 除了将底部标签栏固定在底部之外,是否还存在其他属性? 或
  2. 是否有可能从组件内部更改Android清单windowSoftInputMode? 如果需要其他代码部分作为参考,请在下面评论。感谢任何帮助。

你是想要底部选项卡栏保持可见,但在键盘下方,还是键盘滑过选项卡栏并隐藏它(即模态视图)? - SJT
谢谢回复。接受任何一种解决方案。是的,我需要在键盘打开时隐藏底部选项卡栏。 - Dhevendhiran M
createMaterialBottomTabNavigator来自'react-navigation-material-bottom-tabs',运行完美。更多信息请访问:https://reactnavigation.org/docs/en/material-bottom-tab-navigator.html - hamza erguder
13个回答

46

我使用了React Navigation 5,这是您想要的吗?

<SignedIn.Navigator 
   tabBarOptions={{
      keyboardHidesTabBar: true
   }}         
}>
</SignedIn.Navigator>

这里需要阅读的文档.


8
它可以与默认的 tabBar 一起使用,但是当我提供自己的 tabBar 时(例如: tabBar={(props) => <MyTabBar {...props} />}),它就无法工作。有什么解决方法吗? - Amin Dannak
@AminDannak,你能详细介绍一下你自己的自定义选项卡栏吗? - Chanrithisak Phok
@Pok 类似这样:https://dev.to/baptistearnaud/animated-sliding-tab-bar-in-react-native-58pb - Amin Dannak
@AminDannak,你能分享一段源代码片段吗?仅凭几行代码是无法调试你的代码的。 - Chanrithisak Phok

21

请使用此项

<Tab.Navigator
screenOptions={{
    tabBarHideOnKeyboard: true
 }}
/>

我相信它会完美地工作


tabBarHideOnKeyboard: true在<Tab.Navigator ScreenOptions={{ tabBarHideOnKeyboard: true}}/>中使用 - Mian Muhammad Ramzan
1
您可以使用您帖子下方的[编辑]链接来更改或更新您的答案。 - Suraj Rao
这是 React Navigation v6.x 的正确选项。 - Liam Clark Gutiérrez
那很有用,可以避免双击! - Andrés López Ferro
这对我没有用,Tab键仍然会覆盖在安卓键盘上,然后隐藏。 - undefined

9

只需要打开AndroidManifest.xml文件,在activity标签内更改/添加即可:

android:windowSoftInputMode="adjustPan"

2
我们已经尝试过了,它运行得很好。但是我们必须使用"adjustResize",因为我们在另一个选项卡中使用聊天布局。如果我使用"adjustPan",在聊天布局页面中,整个视图甚至包括标题都会被推上去。因此,我们必须使用"adjustResize"。是否有其他解决方案?如果可以私下联系您,请提供您在任何社交媒体上的联系方式。 - Dhevendhiran M
在你的情况下,android:windowSoftInputMode="adjustPan|adjustResize"又是怎样的呢? - Idan
在这种情况下,它只采用“adjustPan”的行为。只有使用“adjustPan”和“adjustPan | adjustResize”两者都只会产生“adjustPan”行为。 - Dhevendhiran M

8

找到了,只需将底部导航添加到一个视图中,并使该视图的尺寸与屏幕相同即可:

import React from 'react'
import { StyleSheet, Text, View, Dimensions } from 'react-native'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

const { width, height } = Dimensions.get("window")
const Tab = createBottomTabNavigator()

export default function () {
    return (
        <View style={{
            width,
            height,
        }}>
            <Tab.Navigator>
                <Tab.Screen
                    name="Screen1"
                    component={Component}
                />
                <Tab.Screen
                    name="Screen2"
                    component={Component}
                />
                <Tab.Screen
                    name="Screen3"
                    component={Component}
                />
            </Tab.Navigator>
        </View>
    )
}


1
为什么这个能够完美地运行?我不知道,但它就像魔法一样运作。 - prince david
1
哇哇哦!你救了我。它可以工作,但我不知道为什么。这个问题花费了我好几个小时。 - suyuti
1
不!问题仍然存在,但很少见。 :( - suyuti

3
screenOptions={{
          headerShown: false,
          tabBarActiveTintColor: '#1a3c43',
          tabBarInactiveTintColor: '#1a3c43',
          tabBarActiveBackgroundColor: 'white',
          tabBarInactiveBackgroundColor: '#1a3c43',
         
          tabBarHideOnKeyboard: true,
   
          tabBarstyle: {
              backgroundColor: '#1a3c43',
              paddingBottom: 3
          }
      }}

3

我遇到了完全相同的问题。以下是我成功解决它的两种方法。

  1. 在app.json中添加"softwareKeyboardLayoutMode":"pan",如下所示
"android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/adaptive-icon.png",
        "backgroundColor": "#FFFFFF"
      },
      "softwareKeyboardLayoutMode":"pan"
    }

通过这样做,底部导航栏被键盘隐藏了。然而,包含的滚动视图并不按照我想要的方式工作。整个应用屏幕被键盘的高度平移,隐藏了我的一半和它上面的所有内容(标题等)。
第二个解决方法是使用useKeyboard hook。 步骤1:删除"softwareKeyboardLayoutMode",使其默认为height (这会使在整个屏幕被压缩到剩余高度时上升到键盘上方) 步骤2:在键盘激活时动态重置的位置。
在包含的屏幕中
<ScrollView style={{ height: keyboard.keyboardShown? 510 - keyboard.keyboardHeight: 510}}>
/* lots of text inputs*/
</ScrollView>

CustomBottomTabNav 中。
tabBarOptions={{
    ...otherStuff,
    style={{ bottom: keyboard.keyboardShown? -100: -10, ...otherStuff}}
}}

这第二种方法更加可靠。我尝试过 keyboardAvoidingView,但无法理解其不可预测的行为。

我知道这个问题已经被提出了一年多,但我回答是为了未来遇到类似问题的开发人员。 - Suraj Ingle
这个解决方案对我很有效!非常感谢你。 - Caner Kuru
这个解决方案对我很有效!非常感谢你。 - undefined
@CanerKuru 我很高兴能帮到你 - Suraj Ingle

3

在AndroidManifest.xml文件中添加以下代码

android\app\src\main\AndroidManifest.xml

<application
      <!--//......-->
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
         <!-- android:windowSoftInputMode="adjustResize" Change to the following -->       
        android:windowSoftInputMode="stateAlwaysHidden|adjustPan">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>

在 android 文件夹内运行以下命令:

cd android && ./gradlew clean

然后再次进行构建:

npx react-native run-android


1

<Tab.Navigator screenOptions={{ tabBarHideOnKeyboard: Platform.OS!== 'ios'}}>

</Tab.Navigator>

这段代码在React Native中可完美适用于两个平台。


1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - ethry

0

我怀疑这个问题永远不会被关闭,但如果有人碰巧遇到了这个问题并需要答案,我建议查看以下线程:

https://github.com/react-navigation/react-navigation/issues/6700

简而言之,当提供自定义导航栏时,您必须注意在键盘打开时隐藏该栏的操作。这是因为这是默认的Android行为。

因此,要么像作者描述的第一个解决方案那样更改清单配置,但这并不起作用。

要么修改您的组件以便监听React Native的KEYBOARD。keyboardDidShow和keyboardDidHide事件,并使用bottomMargin:-XYZ将其向下移动或使用标志完全隐藏它。

以下两个GitHub上的回复对我有所帮助:

https://github.com/react-navigation/react-navigation/issues/6700#issuecomment-625985764

https://github.com/react-navigation/react-navigation/issues/618#issuecomment-303975621

如果有人想把我的代码作为参考

interface BottomTabStateProps {
// unrelated Props
}

interface BottomTabDispatchProps {
// unrelated service dispatchers
}

interface BottomTabState {
    navVisible: boolean;
}

class BottomTabContainerClass extends React.Component<
    BottomTabStateProps & BottomTabDispatchProps & NavigationInjectedProps, BottomTabState
> {

    constructor(props: BottomTabStateProps & BottomTabDispatchProps & NavigationInjectedProps) {
        super(props);

        this.state = {
        navVisible: true
        };
    }

    componentDidMount() {
        Keyboard.addListener('keyboardDidShow', () => this.keyboardDidShow());
        Keyboard.addListener('keyboardDidHide', () => this.keyboardDidHide());
    }

    componentWillUnmount() {
        Keyboard.removeAllListeners('keyboardDidShow');
        Keyboard.removeAllListeners('keyboardDidHide');
    }


    keyboardDidShow() {
        this.setState({ navVisible: false });
    }

    keyboardDidHide() {
        this.setState({ navVisible: true });
    }

    render() {

        return (
            <View>
                {
                    this.state.navVisible &&
                    <View>
                          // add custom Navbar here
                    </View>
                }
            </View>
        );
    }
}

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接