我正在开发这个Android TV应用程序,该应用程序的一项活动包含一些按钮。单击按钮后,将填充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" />
还有这个:
binding.categoriesRv.setOnFocusChangeListener { v, hasFocus ->
if (!hasFocus)
v.requestFocus()
}
以第二种方式,除非我在RecyclerView中使用android:descendantFocusability="blocksDescendants"
,否则从不调用FocusChangeListener,但这会阻止RecyclerView的项被聚焦。
@Override
public void onAttachedToRecyclerView(final RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
recyclerView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
LinearLayoutManager lm = ((LinearLayoutManager) recyclerView.getLayoutManager());
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
//return false or true; // whatever your case is
} else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
return false;
} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
} else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
} else if (keyCode == KeyEvent.KEYCODE_ENTER) {
} else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
}
}
return false;
}
});
recyclerView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
} else if (!hasFocus) {
}
}
});
}
DPad导航实际上意味着焦点在某些视图之间改变。因此,当您按下Dpad-Right时,谁应该决定焦点应该放在哪里?包含所述Views的ViewGroup可以!
小背景:当一个视图不知道谁应该获得焦点时,它要求ViewGroup做出上述决定。因此,在大多数情况下,当您将焦点对准视图时按DpadRight时,
focusSearch在其容器上被调用的方向为= FOCUS_RIGHT(FOCUS_END)。
为您提供的解决方案非常简单。您有2种方法: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!
else
return null; // someone else will find the next focus
}
});
您可以创建一个自定义视图来扩展您用于recyclerview的任何容器,并执行相同的操作,这是我们使用带有顶部菜单及其下的各个片段的UI的一个更复杂的示例https://gist.github.com/RedLann/bfaffc06eb0f571234c6e46b697d633b注意:通常在xml中,我们在recyclerview
android:descendantFocusability="afterDescendants"
上使用注意:如此一来,当您第一次确定视图的焦点时,就会调用该视图的方法,即:protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect)
注意:如果使用这种方法,焦点管理变得非常容易,每个父视图(ViewGroup / Container)将为其直接子级管理焦点,如果不知道要做什么,可以将其委托给自己的父视图组返回super.focusSearch