防止 Recyclerview 失去焦点

hid*_*s02 2 android android-tv android-recyclerview

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

问题是当使用 DPAD 导航到按钮的方向时, RecyclerView 失去了对按钮的关注。我想防止这种行为,即防止 RecyclerView 失去对活动中其他任何内容的关注。后来,选择另一个按钮的唯一方法是单击后退按钮,这个我可以做到,没问题。

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

<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" />
Run Code Online (Sandbox Code Playgroud)

和这个:

 binding.categoriesRv.setOnFocusChangeListener { v, hasFocus ->
     if (!hasFocus)
        v.requestFocus()
  }
Run Code Online (Sandbox Code Playgroud)

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

小智 10

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

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

DPad 导航实际上意味着某些视图之间的焦点变化。那么当你按下 Dpad-Right 时,谁来决定焦点应该放在哪里?包含视图的 ViewGroup(父)确实如此!

一点背景:当一个视图不知道谁应该获得焦点时,它会要求 ViewGroup 做出决定。因此,在大多数情况下,当您将 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
    }
});
Run Code Online (Sandbox Code Playgroud)
  1. 您可以创建一个自定义视图,扩展您用于回收站视图的任何容器并执行相同操作,这里有一个更复杂的示例,我们将其与具有顶部菜单和其下的各种片段的 UI 一起使用https://gist.github。 com/RedLann/bfaffc06eb0f571234c6e46b697d633b

注意:通常在 xml 中,我们在 recyclerview 上使用android:descendantFocusability="afterDescendants" 注意:只是为了让您知道当视图第一次获得焦点时,会调用该视图的一个方法,即:

protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect)
Run Code Online (Sandbox Code Playgroud)

注意:如果您使用这种方法,焦点管理变得非常简单,每个父视图(ViewGroup/Container)都将管理其直接子视图的焦点,当它不知道该怎么做时,它可以委托给自己的父视图组返回 super .focusSearch