25

Is it possible to change the accessibility focus order? For example, if I have 3 views side by side, with ids view1, view2, and view3, is there a simple way to make the accessibility focus go to view3 when the user swipes right from view1?

Here is what I've tried:

I have the following in a linear layout.

<ImageView
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:id="@+id/imageView"
    android:focusable="true"
    android:nextFocusUp="@+id/imageView3"
    android:nextFocusDown="@+id/imageView3"
    android:nextFocusRight="@+id/imageView3"
    android:nextFocusLeft="@+id/imageView3"
    android:nextFocusForward="@+id/imageView3"
    android:src="@drawable/ic_launcher"/>

<ImageView
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:id="@+id/imageView2"
    android:focusable="true"
    android:src="@drawable/ic_launcher"/>

<ImageView
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:id="@+id/imageView3"
    android:focusable="true"
    android:nextFocusUp="@+id/imageView2"
    android:nextFocusDown="@+id/imageView2"
    android:nextFocusRight="@+id/imageView2"
    android:nextFocusLeft="@+id/imageView2"
    android:nextFocusForward="@+id/imageView2"
    android:src="@drawable/ic_launcher"/>

Then, I launch this and place accessibility focus on the first imageView. Upon swiping right to move to the next item, I expect it to move accessibility focus to imageView3, but instead it goes to imageView2.

rds
  • 26,253
  • 19
  • 107
  • 134
Allen Z.
  • 340
  • 1
  • 5
  • 10
  • 3
    Technically yes, you can explicitly specify traversal order if you set an AccessibilityDelegate and add the child nodes manually, but this causes other issues and isn't guaranteed to work if TalkBack changes how it handles focus traversal. It's still an open feature request against the accessibility framework. – alanv Nov 04 '14 at 20:42
  • @alanv Do you happen to have a link to the outstanding feature request? I'd love to follow its' progress. Changing the traversal order would be especially helpful for the new Floating Action Button. If it is floating over an auto-loading list, a user might not ever find it by swiping right. (See Inbox for example of this issue) – Kio Krofovitch Jun 02 '15 at 08:35
  • Nevermind, looks like it was just added in API 22! Added an answer to the original quesiton. – Kio Krofovitch Jun 02 '15 at 08:50

1 Answers1

47

For applications with minSdkVersion >= 22, you may set the traversal order for screen readers direct in the XML with android:accessibilityTraversalAfter:

<ImageView
    android:id="@+id/imageView"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:src="@drawable/ic_launcher" />

<ImageView
    android:id="@+id/imageView2"
    android:layout_width="30dp"
    android:accessibilityTraversalAfter="@id/imageView3"
    android:layout_height="30dp"
    android:src="@drawable/ic_launcher" />

<ImageView
    android:id="@+id/imageView3"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:src="@drawable/ic_launcher" />

For applications supporting lower API levels, the traversal order may be set programmatically with ViewCompat:

ViewCompat.setAccessibilityDelegate(imageView2, object : AccessibilityDelegateCompat() {
    override fun onInitializeAccessibilityNodeInfo(host: View?, info: AccessibilityNodeInfoCompat?) {
        info?.setTraversalAfter(imageView3)
        super.onInitializeAccessibilityNodeInfo(host, info)
    }
})

Please keep in mind that screen reader users rely on the consistency of the navigation, therefore, changing the focus order is an anti-pattern and should be avoided.

Diego Malone
  • 1,044
  • 9
  • 25
Kio Krofovitch
  • 2,954
  • 1
  • 21
  • 30
  • 11
    Is there any solution for this for versions < 22? – vtlinh Oct 12 '16 at 19:44
  • 3
    I think @vtlinh question is even more important than the original one. 22 is too recent. Does anyone know what's the solution for older versions? – Carlos Apr 18 '17 at 13:38
  • 3
    I experience issues using this in a `RecyclerView` item. It jumps to next item of the list after traversing on current item. – azizbekian Jul 28 '17 at 09:31
  • 3
    @Carlos @vtlinh It seems there is a compat class for it: [AccessibilityNodeInfoCompat](https://developer.android.com/reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html). It contains methods `setTraversalBefore` and `setTraversalAfter` – user3829751 Nov 16 '17 at 20:19
  • 3
    for anyone trying this, it only work >= 22. Their is no solution for <22. – Saurabh Oct 24 '19 at 05:56
  • In case image3 is gone this won't work. Is there some way to solve this? – Nicolás Arias May 21 '20 at 22:05
  • Didn't work for me, neither `setTraversalAfter` nor `setTraversalBefore`. Still reads as A1, B1, A2, C1, B2. But what I want is A1, A2, B1, B2, C1; where A1 is a textview on left and A2 is a textview on the right side, B1B2 the same but under A1A2, etc; all under a `ConstraintLayout`. – Dr.jacky Nov 25 '21 at 12:34