Android 修复在 Settings 首页,按键盘方向键逐个单选

Android 修复在 Settings 首页,按键盘方向键逐个单选

问题现象

在 Settings 主界面,按键盘方向键上下会直接整个选中,无法单条选中变色,而在二级页面中按方向键上下是正常的。

没有遥控器可以通过 adb 指令模拟下键

adb shell input keyevent 20

问题分析

Settings 中都是用的 Preference 控件来显示界面的,既然二级页面可以,主界面不行的话,那应该是主界面布局有问题。

盲猜和焦点占用有关系,找到主界面布局文件 settings_homepage_container.xml

java 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/settings_homepage_container"
    android:fitsSystemWindows="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

	<androidx.core.widget.NestedScrollView
        android:id="@+id/main_content_scrollable_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="com.android.settings.widget.FloatingAppBarScrollingViewBehavior"> 

        <LinearLayout
            android:id="@+id/homepage_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <FrameLayout
                android:id="@+id/contextual_cards_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="@dimen/contextual_card_side_margin"
                android:layout_marginEnd="@dimen/contextual_card_side_margin"/>

            <FrameLayout
                android:id="@+id/main_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:animateLayoutChanges="true"
                android:background="?android:attr/windowBackground"/>

      </LinearLayout>
    </androidx.core.widget.NestedScrollView>

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:touchscreenBlocksFocus="false"
        android:keyboardNavigationCluster="false">
        <include layout="@layout/search_bar"/>
    </com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

可以看到主界面加载的 Preference 最终都是在 main_content 中

层级结构

NestedScrollView

LinearLayout

FrameLayout

Preference

经过验证发现,焦点被最外层 NestedScrollView 处理了,无法传递到 Preference 中,所以就无法单条选中

分析了下 PreferenceScreen 本身就具有屏幕显示不全时可滚动的机制,

谷歌在这最外面又包了一个 NestedScrollView 岂不是多此一举,其实不是这样的,是因为里面还有其它数据,

看到 contextual_cards_content 这个,是用来装 Suggestion 菜单的,为了整体能够滚动,所以套了一个 NestedScrollView

为了事件能过直接被 PreferenceScreen 捕获,

参考了这篇 https://blog.51cto.com/u_15073486/5363888 发现没啥用,而且还浪费时间。。

一开始尝试了通过事件传递回调的方式,试了好几种发现都不行(如果你能成功可以反馈给我),

后来直接将外层的 NestedScrollView 和 LinearLayout 干掉,

这样做虽然可以让主界面单条选中,但弊端是牺牲了 Suggestion 功能。

解决办法

干掉 NestedScrollView,将 homepage_container 和 contextual_cards_content 都设置成 gone,避免编译报错

java 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/settings_homepage_container"
    android:fitsSystemWindows="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<!--     <androidx.core.widget.NestedScrollView
        android:id="@+id/main_content_scrollable_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="com.android.settings.widget.FloatingAppBarScrollingViewBehavior"> -->

        <LinearLayout
            android:visibility="gone"
            android:id="@+id/homepage_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"/>

            <FrameLayout
                android:visibility="gone"
                android:id="@+id/contextual_cards_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="@dimen/contextual_card_side_margin"
                android:layout_marginEnd="@dimen/contextual_card_side_margin"/>

            <FrameLayout
                android:id="@+id/main_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:animateLayoutChanges="true"
                android:background="?android:attr/windowBackground"/>

       <!--  </LinearLayout>
    </androidx.core.widget.NestedScrollView> -->

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:touchscreenBlocksFocus="false"
        android:keyboardNavigationCluster="false">
        <include layout="@layout/search_bar"/>
    </com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
相关推荐
zh_xuan31 分钟前
Android Looper源码阅读
android
用户02738518402611 小时前
[Android]RecycleView的item用法
android
前行的小黑炭11 小时前
Android :为APK注入“脂肪”,论Android垃圾代码在安全加固中的作用
android·kotlin
帅得不敢出门12 小时前
Docker安装Ubuntu搭建Android SDK编译环境
android·ubuntu·docker
tangweiguo0305198713 小时前
Android Kotlin 动态注册 Broadcast 的完整封装方案
android·kotlin
fatiaozhang952713 小时前
浪潮CD1000-移动云电脑-RK3528芯片-2+32G-安卓9-2种开启ADB ROOT刷机教程方法
android·网络·adb·电脑·电视盒子·刷机固件·机顶盒刷机
前行的小黑炭13 小时前
Android 不同构建模式下使用不同类的例子:如何在debug模式和release模式,让其使用不同的类呢?
android·kotlin·gradle
andyguo14 小时前
AI模型测评平台工程化实战十二讲(第一讲:从手工测试到系统化的觉醒)
android
2501_9159214314 小时前
小团队如何高效完成 uni-app iOS 上架,从分工到工具组合的实战经验
android·ios·小程序·uni-app·cocoa·iphone·webview
幂简集成14 小时前
通义灵码 AI 程序员低代码 API 课程实战教程
android·人工智能·深度学习·神经网络·低代码·rxjava