Программно «вращающийся» фокус - PullRequest
0 голосов
/ 09 апреля 2020

У меня есть макет, и я хочу программно переключать фокус между представлениями. Мне довелось реализовать то, что вращает фокус, как группу представлений. У моего макета есть 3 элемента: текстовое представление и 2 кнопки:

<?xml version="1.0" encoding="utf-8"?>
<AccessContainer2 xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".AccessActivity">

    <TextView
        android:id="@+id/text_hello_world"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Hello World!"
        android:nextFocusForward="@id/button_option_1"
        android:focusable="true"
        android:focusableInTouchMode="true">

        <requestFocus/>
    </TextView>

    <LinearLayout
        android:id="@+id/buttons"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:descendantFocusability="afterDescendants">

        <Button
            android:id="@+id/button_option_1"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="Option 1"
            android:nextFocusForward="@id/button_option_2"
            android:focusable="true"
            android:focusableInTouchMode="true" />

        <Button
            android:id="@+id/button_option_2"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="Option 2"
            android:nextFocusForward="@id/text_hello_world"
            android:focusable="true"
            android:focusableInTouchMode="true" />
    </LinearLayout>
</AccessContainer2>

Я попытался определить «прямую» фокусировку для каждого из 3 фокусируемых элементов в виде текстового представления, кнопка 1, кнопка 2 и возвращаемся к текстовому представлению.

Мой код в моей группе представлений выглядит следующим образом:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    final View currentFocus = getFocusedChild();
    if (currentFocus == null) {
        Log.w(TAG, "No current focus!");
    } else {
        Log.i(TAG, String.format("Currently focused child view ID: %s", getId(currentFocus)));
        View newFocus = focusSearch(currentFocus, FOCUS_FORWARD);
        Log.i(TAG, String.format("New child to focus view ID: %s", getId(newFocus)));
        if (!newFocus.requestFocus()) {
            Log.w(TAG, String.format("Failed to focus new child view ID: %s", getId(newFocus)));
        }
    }
    return true;
}

Итак,

  1. Найти текущий фокус.
  2. Найдите из этого следующий "прямой" фокус.
  3. Установите его на текущий фокус.

Однако я получаю такой результат:

04-08 14:51:33.600 14232 14232 I AccessContainer2: Currently focused child view ID: com.clover.accesswork:id/text_hello_world
04-08 14:51:33.600 14232 14232 I AccessContainer2: New child to focus view ID: com.clover.accesswork:id/button_option_1
04-08 14:51:34.721 14232 14232 I AccessContainer2: Currently focused child view ID: com.clover.accesswork:id/buttons
04-08 14:51:34.724 14232 14232 I AccessContainer2: New child to focus view ID: com.clover.accesswork:id/text_hello_world

Таким образом, при первом касании он находит button_option_1 в качестве следующего фокуса, но когда я вызываю на нем фокус запроса, он устанавливает контейнер (кнопки) этого представления в качестве фокуса ... хотя я явно сказал, что макет не фокусируемость и то, что он должен предпочитать фокусировать своих потомков (хотя я не думаю, что это должно требоваться на линейном расположении, а только на попытках).

Есть идеи?

1 Ответ

0 голосов
/ 09 апреля 2020

Это ошибка "RTFM". Оказывается, что getFocusedChild() задокументировано как:

Возвращает сфокусированного потомка этого представления, если оно есть. Ребенок может иметь фокус или содержать фокус.

Таким образом, в этом случае он возвращал вид, содержащий фокус, а не ребенка с фокусом. Я написал эту функцию, чтобы получить дочернее представление, которое на самом деле имеет фокус:

private View getFocused(ViewGroup vg) {
    View focused = vg.getFocusedChild();
    if (focused == null) {
        return null;
    }
    if (focused instanceof ViewGroup) {
        // Figure out if a child of the view group has focus
        // Recursion!
        View v = getFocused((ViewGroup) focused);
        if (v == null) {
            // The view group itself actually has focus
            return focused;
        } else {
            // A child of the view group had focus
            return v;
        }
    }
    // A non-view group child had focus
    return focused;
}
...