导航手势导航键在input部分的差别

背景:

在课程车载多屏互动动画专题学习时候有一部分学员在apply patch发现有如下问题

在这里插入图片描述

只能拖到一小段,然后在接收事件的部分就收到了一个CANCEL事件,但是在导航手势模式下却没有该问题。

探索分析原因

那么到底啥原因导致的CANCEL事件产生呢?这个其实就需要对相关的InputDispatch代码进行详细的分析了。

在三个按钮导航键情况下,抓相关的InputDispatcher日志(注意开一些TAG以及要自己加一些log)

在这里插入图片描述

复现问题获取日志如下:

图片

简单说就是在多屏互动过程中,需要把Activity从这个屏幕移动到另一个屏幕,必然就导致原来屏幕的Activity相关会有移除,体现在input端就是相关的InputWindow会被remove,这个时候input派发事件发现根本没有可以用的window了,所以自然就无法派发事件了,因为不知道派发给谁。

这里大家会有疑问导航手势难道没有移除么?它为啥可以正常派发?

这里也同样抓取一下相关的日志看看:

图片

上面InputDispatcher日志就详细展现了为啥导航手势没有触发相关的CANCEL事件,因为它们有Gesture Monitor这中InputWindow存在于input,导致派发windows不会为none。

至于详细的普通Monitor和Gesture Monitor详细差别可以看以前发布的这篇文章:

Android13上两种监控屏幕input输入的方式–学员投稿

更多framework技术干货,请关注下面“千里马学框架”

<think>我们正在解决Android应用中导航栏被输入法键盘覆盖的问题。根据引用[1]到[5],我们可以总结出几种解决方案: 1. 使用ScrollView包装布局,并设置android:windowSoftInputMode="adjustResize"(引用[1])。 2. 在Activity的AndroidManifest.xml中设置android:windowSoftInputMode="adjustPan"(引用[4]和引用[5])。 3. 使用WindowInsets API进行自定义处理(引用[1])。 4. 对于沉浸式状态栏问题,检查主题设置(引用[2]和引用[3])。 用户的问题聚焦在导航栏被键盘覆盖,所以我们重点考虑调整窗口软键盘模式。 步骤: 1. 调整Activity的窗口软键盘模式:在AndroidManifest.xml中为对应的Activity设置android:windowSoftInputMode属性。 选项: - "adjustResize":调整窗口大小,为软键盘腾出空间,这样布局会重新计算大小,通常配合ScrollView使用。 - "adjustPan":平移窗口内容,避免键盘覆盖当前焦点,但可能不会调整底部导航栏。 2. 如果使用adjustResize,确保布局是可滚动的(如使用ScrollView),这样当键盘弹出时,用户可以通过滚动看到被遮挡的部分。 3. 如果底部导航栏是固定在底部的(如BottomNavigationView),并且被键盘覆盖,那么可能需要结合adjustResize和布局调整,确保导航栏在键盘上方。 4. 对于Fragment,同样可以在承它的Activity中设置(引用[5])。 5. 如果上述方法无效,可能需要使用WindowInsets API(Android 5.0及以上)自定义处理键盘与导航栏的交互(引用[1])。 具体代码示例: 方法一:使用adjustPan(简单,但可能只解决输入框焦点问题,不一定能解决底部导航栏被覆盖) 在AndroidManifest.xml中: ```xml <activity android:name=".MainActivity" android:windowSoftInputMode="adjustPan"> </activity> ``` 方法二:使用adjustResize,并配合ScrollView(推荐,但需要调整布局) 首先,在AndroidManifest.xml中设置: ```xml <activity android:name=".MainActivity" android:windowSoftInputMode="adjustResize"> </activity> ``` 然后,确保布局最外层是ScrollView(或类似的可滚动容器): ```xml <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <!-- 你的布局内容 --> <!-- 注意:如果布局中有固定底部的导航栏,需要将它放在ScrollView外面,否则它也会被滚动 --> </ScrollView> ``` 但是,如果底部导航栏需要固定在底部,不随内容滚动,那么可以使用CoordinatorLayout或RelativeLayout等,将导航栏放在底部,其余内容放在可滚动区域。 例如,使用CoordinatorLayout和AppBarLayout、NestedScrollView(支持嵌套滚动)和BottomNavigationView: ```xml <androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <!-- 主要内容区域 --> </androidx.core.widget.NestedScrollView> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_navigation" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" /> </androidx.coordinatorlayout.widget.CoordinatorLayout> ``` 这样,当键盘弹出时,由于设置了adjustResize,整个窗口会调整大小,NestedScrollView会重新计算高度,而底部导航栏会保持在底部,并且不会被键盘覆盖(因为键盘弹出时,窗口底部会向上收缩,导航栏会紧贴键盘上方)。 方法三:自定义WindowInsets(更灵活,但更复杂) 在Activity的onCreate中,可以监听根视图的WindowInsets变化,然后调整底部导航栏的位置。 例如,在Activity中: ```java View rootView = findViewById(android.R.id.content); ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, insets) -> { int bottomInset = insets.getSystemWindowInsetBottom(); // 获取底部导航栏视图 BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation); // 设置底部导航栏的底部边距为系统窗口的底部插入(即键盘高度) ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) bottomNav.getLayoutParams(); params.bottomMargin = bottomInset; bottomNav.setLayoutParams(params); return insets; }); ``` 注意:这种方法需要API 21以上,并且需要处理初始状态和状态变化。 总结: 推荐优先尝试方法二(adjustResize配合合适的布局),如果布局复杂或者需要更精细的控制,再考虑方法三。 根据引用[3]和[4],还有一点需要注意:如果使用了沉浸式状态栏(透明状态栏),可能会遇到其他问题,需要检查主题设置。但当前问题主要是键盘覆盖导航栏,所以先解决键盘问题。 请根据你的实际布局选择合适的方法。</think>### Android导航栏被键盘覆盖的解决方案 在Android应用中,当软键盘弹出时,底部导航栏可能被覆盖或布局出现异常。以下是五种经过验证的解决方案: --- ### 1. **调整窗口软键盘模式**(推荐) 在`AndroidManifest.xml`中为Activity添加属性: ```xml <activity android:name=".MainActivity" android:windowSoftInputMode="adjustResize|adjustPan"> </activity> ``` - **`adjustResize`**:自动调整布局大小,为键盘腾出空间 - **`adjustPan`**:平移窗口内容,避免焦点控件被遮挡 > 两者可组合使用(API 19+)[^4][^5] --- ### 2. **使用ScrollView包装布局** ```xml <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <!-- 内容区域 --> </LinearLayout> </ScrollView> ``` - 当键盘弹出时,系统自动启用滚动条 - 需配合`android:windowSoftInputMode="adjustResize"`[^1] --- ### 3. **自定义WindowInsets处理**(API 20+) 在Activity中监听布局变化: ```kotlin ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) binding.bottomNav.translationY = -systemBars.bottom.toFloat() // 上移导航栏 insets } ``` - 动态调整导航栏位置 - 支持全面手势导航[^1] --- ### 4. **修复沉浸式状态栏冲突** 在`styles.xml`中添加: ```xml <style name="AppTheme" parent="Theme.MaterialComponents.Light"> <item name="android:windowDrawsSystemBarBackgrounds">false</item> </style> ``` - 防止状态栏蒙层影响布局计算[^3] --- ### 5. **协调布局嵌套**(针对复杂UI) ```xml <CoordinatorLayout> <AppBarLayout>...</AppBarLayout> <NestedScrollView app:layout_behavior="@string/appbar_scrolling_view_behavior"> <!-- 可滚动内容 --> </NestedScrollView> <BottomNavigationView android:layout_gravity="bottom"/> <!-- 固定底部 --> </CoordinatorLayout> ``` - 确保导航栏始终位于键盘上方[^1] --- ### 选择建议: | 方案 | 适用场景 | 复杂度 | |------|----------|--------| | 窗口模式调整 | 简单布局 | ⭐ | | ScrollView | 表单类界面 | ⭐⭐ | | WindowInsets API | 全面/手势导航 | ⭐⭐⭐ | | 协调布局 | 复杂交互界面 | ⭐⭐ | > **关键提示**: > 1. 测试时使用`adb shell ime set com.android.inputmethod.latin/.LatinIME`模拟键盘 > 2. 避免`adjustNothing`,会导致布局异常[^4] > 3. 在`onCreate()`中调用`getWindow().setSoftInputMode()`可动态修改行为
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值