Предотвратить Recyclerview от потери фокуса - PullRequest
0 голосов
/ 14 февраля 2020

Я разрабатываю это 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" />

И это:

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

Во втором случае FocusChangeListener никогда не вызывается, если я не использую android:descendantFocusability="blocksDescendants" в RecyclerView, но это предотвращает фокусирование элементов RecyclerView.

Ответы [ 3 ]

3 голосов
/ 20 февраля 2020

Прежде всего, я работал в течение 3 лет над AndroidTv, борясь с управлением фокусом, на самом деле это довольно просто, проблема в том ... нет документации!

На Android -ТВ право Способ управления навигацией Dpad заключается в использовании метода focusSearch. Что это делает?

DPad навигация фактически означает, что фокус изменяется между некоторыми представлениями. Итак, кто должен решить, где фокус должен go, когда вы нажимаете Dpad-Right? ViewGroup (родитель), содержащий представления, делает!

Небольшой фон: когда представление не знает, кто должен получить фокус, оно просит ViewGroup принять решение. Поэтому в большинстве случаев, когда вы выполняете sh DpadRight, находясь в фокусе на представлении, focusSearch вызывается для его контейнера с direction = 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! DO NOT return recyclerview, but focused, which is a child of the recyclerview
        else
            return null; // someone else will find the next focus
    }
});
Вы можете создать собственное представление, расширяющее любой контейнер, который вы используете для своего повторного просмотра, и сделать то же самое, вот немного более сложный пример, который мы используем с пользовательским интерфейсом, имеющим верхнее меню и различные фрагменты под ним https://gist.github.com/RedLann/bfaffc06eb0f571234c6e46b697d633b

ПРИМЕЧАНИЕ. Обычно в xml мы используем на представлении реселлера android:descendantFocusability="afterDescendants" ПРИМЕЧАНИЕ. Просто для того, чтобы вы знали, когда представление фокусируется в первый раз, существует метод этого представления. это называется:

protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect)

ПРИМЕЧАНИЕ. Если вы используете этот подход, управление фокусом становится действительно простым, каждое родительское представление (ViewGroup / Container) будет управлять фокусом для своих прямых потомков, когда это не так. не знает, что делать, он может делегировать свою родительскую группу просмотра, возвращая super.focusSearch

0 голосов
/ 19 февраля 2020

Этого можно добиться, внедрив ключевые прослушиватели в свои элементы управления и просмотр и перерабатывай это вручную.

Добавьте приведенный ниже метод в свой класс адаптера и определите каждый шаг, который вы хотите выполнять при каждом нажатии. Он работает в моем приложении, надеюсь, он вам тоже поможет.

@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) {

            }
        }
    });
}
0 голосов
/ 19 февраля 2020

Независимо от того, что вы делаете, если вы используете переработчик в телевизионном приложении android, оно потеряет фокус. Единственное решение - использовать отрывные фрагменты.

...