Изменить порядок чтения элементов в фокусируемой ViewGroup - PullRequest
1 голос
/ 25 сентября 2019

В моем приложении есть несколько экранов, на которых TalkBack не определяет правильный порядок чтения.Согласно документации, я могу использовать android:accessibilityTraversalAfter и друзей, чтобы изменить порядок чтения.Но это не работает для меня в элементах в пределах фокусируемого ViewGroup, который должен быть прочитан вместе.

Весь макет выглядит так:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:accessibilityTraversalBefore="@id/before"
    android:focusable="true"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/before"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:accessibilityTraversalAfter="@id/before"
        android:text="Before"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

    <TextView
        android:id="@+id/after"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:accessibilityTraversalBefore="@id/after"
        android:text="After"
        app:layout_constraintBottom_toTopOf="@+id/before"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Он отображает After всередина экрана, Before внизу.Я хочу, чтобы TalkBack рассматривал весь экран как один непрерывный элемент, поэтому я установил android:focusable на true.По умолчанию TalkBack читает: «После, до» .Но я хочу, чтобы он прочитал «До, после» .Хотя я добавил android:accessibilityTraversalBefore и android:accessibilityTraversalAfter, он все равно читает «После, до» .Вот результат отладки дерева узлов:

TreeDebug: (-2147455381)429.FrameLayout:(0, 0 - 1080, 1920):A
TreeDebug:   (30189)429.TextView:(42, 101 - 397, 172):TEXT{My Application}:A:supportsTextLocation
TreeDebug:   (31150)429.ViewGroup:(0, 210 - 1080, 1794):Fa:focusable:accessibilityFocused
TreeDebug:     (33072)429.TextView:(499, 951 - 581, 1002):TEXT{After}:A:supportsTextLocation
TreeDebug:     (32111)429.TextView:(485, 1743 - 595, 1794):TEXT{Before}:A:supportsTextLocation

Что я делаю не так?

Просто для полноты: minSdkVersion равно 26, targetSdkVersion равно 29.

1 Ответ

1 голос
/ 28 сентября 2019

Я углубился в проблему и обнаружил следующее: accessibilityTraversalBefore и accessibilityTraversalAfter флаги в деле вступают в силу, но только для того, для чего они предназначены - они предназначены для приложения Accessibility Service (например, Talkback).Другими словами, если вы удалите атрибут focusable из корневого макета, вы увидите, что навигация верна.

Но эти флаги не влияют на то, как AccessibilityNode построен для корня ViewGroup.Как видно из источников ViewGroup#onInitializeAccessibilityNodeInfoInternal(), фактическая логика построения текста не учитывает, как дети строят свою навигацию, используя верхние упомянутые флаги.

Чтобы решитьпроблема, я удалил чрезмерные флаги из макета XML как таковой:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusable="true"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/before"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:importantForAccessibility="no"
        android:text="Before"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/after"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:importantForAccessibility="no"
        android:text="After"
        app:layout_constraintBottom_toTopOf="@+id/before"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

И внутри действия / фрагмента хоста:

val root = findViewById<ViewGroup>(R.id.root)

ViewCompat.setAccessibilityDelegate(root, object : AccessibilityDelegateCompat() {
    override fun onInitializeAccessibilityNodeInfo(
        host: View?,
        info: AccessibilityNodeInfoCompat?
    ) {
        val stringBuilder = StringBuilder()
        root.children.forEach { view ->
            val label = if (view is TextView) view.text else ""
            stringBuilder.append("$label, ")
        }

        info?.text = stringBuilder.toString()
        super.onInitializeAccessibilityNodeInfo(host, info)
    }
})

Это приведет к желаемому результату: Talkback будет "До, После" .

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

...