android - 防止 Recyclerview 失去焦点

标签 android android-recyclerview android-tv

我正在开发这个 android TV 应用程序,它有一个包含一些按钮的 Activity 。单击按钮后,RecyclerView(在同一个 Activity 中)被填充并自动聚焦。

问题是当使用 DPAD 向按钮方向导航时,RecyclerView 失去对按钮的焦点。我想防止这种行为,即防止 RecyclerView 失去对 Activity 的其他任何东西的关注。后来,选择另一个按钮的唯一方法是单击返回按钮,这个我可以做到,没问题。

这是我尝试过的,但没有奏效:

<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/categories_rv"
        android:layout_width="@dimen/categories_list_width"
        android:layout_height="wrap_content"
        android:focusable="true"
        android:nextFocusForward="@id/categories_rv"
        android:nextFocusUp="@id/categories_rv"
        android:nextFocusRight="@id/categories_rv"
        android:nextFocusLeft="@id/categories_rv"
        android:nextFocusDown="@id/categories_rv"
        android:focusableInTouchMode="true" />

和这个:
 binding.categoriesRv.setOnFocusChangeListener { v, hasFocus ->
     if (!hasFocus)
        v.requestFocus()
  }

在第二种方式中,除非我使用 android:descendantFocusability="blocksDescendants",否则永远不会调用 FocusChangeListener在 RecyclerView 中,但这会阻止 RecyclerView 的项目被聚焦。

最佳答案

首先,我在 AndroidTv 上工作了 3 年,与焦点管理作斗争,实际上很简单,问题是......没有文档!

在 Android-TV 上,管理 Dpad 导航的正确方法实际上是使用 focusSearch 方法。这是做什么的?

DPad 导航实际上意味着一些 View 之间的焦点变化。那么当你按下 Dpad-Right 时,谁来决定焦点应该在哪里呢?包含 View 的 ViewGroup(父级)可以!

一点背景知识:当 View 不知道谁应该获得焦点时,它会要求 ViewGroup 做出决定。因此,在大多数情况下,当您在关注 View 时按下 DpadRight, focusSearch 在其容器上被调用 方向 = FOCUS_RIGHT (FOCUS_END) 等等。

那么,您的解决方案非常简单。你有两种方法:
1. 将 Recyclerview 放在 BrowseFrameLayout 中,然后您可以执行以下操作

BrowseFrameLayout browseFrameLayout = view.findViewById(R.id.recyclerview_container);
RecyclerView recyclerView = view.findViewById(R.id.categories_rv);
theBrowseFrameLayout.setOnFocusSearchListener(new BrowseFrameLayout.OnFocusSearchListener() {
    @Override
    public View onFocusSearch(View focused, int direction) {
        if (recyclerView.hasFocus())
            return focused; // keep focus on recyclerview! DO NOT return recyclerview, but focused, which is a child of the recyclerview
        else
            return null; // someone else will find the next focus
    }
});
  • 您可以创建一个自定义 View 来扩展您用于回收站 View 的任何容器并执行相同操作,这里有一个更复杂的示例,我们使用具有顶部菜单和其下的各种 fragment 的 UI https://gist.github.com/RedLann/bfaffc06eb0f571234c6e46b697d633b

  • 注意:通常在我们在 recyclerview android:descendantFocusability="afterDescendants" 上使用的 xml 中
    注意:为了让您知道 View 第一次获得焦点时,该 View 的一个方法被调用,即:
    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect)
    

    注意:如果您使用这种方法,焦点管理变得非常容易,每个父 View (ViewGroup/Container)将为其直接 subview 管理焦点,当它不知道该做什么时,它可以委托(delegate)给它自己的父 View 组返回 super .focus搜索

    关于android - 防止 Recyclerview 失去焦点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60223322/

    相关文章:

    android - Android Studio 中的 "Requiring Wifi permissions limits app availability on TVs that support only Ethernet"警告 - 有什么办法可以解决这个问题吗?

    android - 如何在 Android TV 上显示数字软件键盘?

    android - 如何制作正确大小的图像以在我的 Android 应用程序中使用

    android - 开始自动下载

    android - 用于内容加载的占位符列表项,例如 facebook

    java - 无法编写基于每个项目保存的长期过滤掉 RecyclerView 中的项目的算法

    android - 关闭没有动画的抽屉导航

    android - 程序类型已经存在:com.loopj.android.http.AsyncHttpClient $ 3

    android - Android RecyclerView SubmitList无法在LiveData观察器中更新数据

    android - 在 4k 屏幕上的 WebView 中显示的内容似乎分辨率很低