Search code examples
androidlistviewfootertalkback

Android How do i stop TalkBack including footer row when reading list items count


I have a dialog containing a list of notes, and I want to make the user scroll to the end of the list to find the "OK" button to close the dialog.

The dialog contains a ListView and I add the button to the list using the footer row.

View footerView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).
                inflate(R.layout.list_footer_button, null, false);
listView.addFooterView(footerView);

When i turn on talk back and open this dialog, it reads the wrong count for the ListView as it is including the footer row. For example if my list has 3 items, talkback reads "Item 1 of 4".

ISSUE

How can i get talkBack to read the correct number of items ignoring the footer row?

OR

If i can't change this, how else do i create a dialog where the user has to scroll to the end of the list before seeing the button to dismiss the dialog.


Solution

  • I have resolved this issue by adding the button to the View for the last row rather than adding a footer.

    My layout for each row contains a textView and a button, and the button is set to be "invisible".

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    
        <LinearLayout android:id="@+id/notes_details"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <!-- other views here but removed for this post -->
            <TextView
                android:id="@+id/notes_text"
                style="@style/notes_text_style"/>
        </LinearLayout>
    
        <Button
            android:id="@+id/notes_button"
            style="@style/notes_button"
            android:layout_below="@id/notes_details"
            android:layout_centerHorizontal="true"
            android:visibility="invisible" />
    
    </RelativeLayout>
    

    In the adapter for the list, I show/hide the button based on whether the row is the last row

     boolean isLastRow = iPosition == getCount()-1;
     okButton.setVisibility(isLastRow ? View.VISIBLE : View.GONE);
    

    Accessibility changes needed

    There was additional work to make this all work for Accessibility purposes. If no changes were made to support accessibility, only the rows are navigatable. Therefore the last row will select the notes text and OK button as one selectable item and you would not be able to navigate to the button using a keyboard/trackerball.

    Firstly you have to set the list so that items in a row are focusable

    listView.setItemsCanFocus(true);
    

    Secondly, in code in the adapter, i set the focusable/nextFocusXXX on the notes textView and button accordingly

    // when in accessibility mode, we want to set the navigation order for
    // the list item's text and the OK button
    boolean isLastRow = iPosition == getCount()-1;
    if (isAccessibilityEnabled) {
        notesTextView.setFocusable(true);
        okButton.setFocusable(true);
        rowView.setNextFocusForwardId(isLastRow ? R.id.notes_button: R.id.notes_text);
        rowView.setNextFocusDownId(isLastRow ? R.id.notes_button: R.id.notes_text);
        okButton.setNextFocusUpId(R.id.notes_text);
    }