Modify accessibility focus order

24,893

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.

Share:
24,893

Related videos on Youtube

Allen Z.
Author by

Allen Z.

Updated on April 19, 2021

Comments

  • Allen Z.
    Allen Z. about 3 years

    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.

    • alanv
      alanv over 9 years
      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.
    • Kio Krofovitch
      Kio Krofovitch about 9 years
      @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
      Kio Krofovitch about 9 years
      Nevermind, looks like it was just added in API 22! Added an answer to the original quesiton.
  • vtlinh
    vtlinh over 7 years
    Is there any solution for this for versions < 22?
  • Carlos
    Carlos about 7 years
    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?
  • azizbekian
    azizbekian almost 7 years
    I experience issues using this in a RecyclerView item. It jumps to next item of the list after traversing on current item.
  • user3829751
    user3829751 over 6 years
    @Carlos @vtlinh It seems there is a compat class for it: AccessibilityNodeInfoCompat. It contains methods setTraversalBefore and setTraversalAfter
  • Saurabh
    Saurabh over 4 years
    for anyone trying this, it only work >= 22. Their is no solution for <22.
  • Nicolás Arias
    Nicolás Arias about 4 years
    In case image3 is gone this won't work. Is there some way to solve this?
  • Dr.jacky
    Dr.jacky over 2 years
    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.