Reputation: 33
I'm currently struggling to create PagerTabStrip
with more TalkBack
vocalization.
The context is:
TalkBack
user.TalkBack
to focus the center tab.I already succeeded partially doing it by rewriting all the needed classes (for instance: PagerTitleStrip
, ViewPager
, FragmentPagerAdapter
) and adding the right contentDescription
directly on the tab TextView
. It works rather well but i'm not satisfied. The maintenance of those classes need to be updated for each new versions of the Android main classes (or i will keep the old design) and i find dirty to copy paste all the class content each time (and what about the next developers ?).
So, I tried another approches:
AccessibilityEvent
in a subclass of PagerTabStrip
to give more context to vocalization. It did not work because getText()
and getContentDescription
methods in AccessibilityEvent
are not used for vocalization. AccessibilityNodeInfo
from ViewPager
to see if i could work it out. But I have not identify the source of the vocalization (is it tabs or content) nor what must be changed in AccessiblityNodeInfo
to change vocalization.So, i wonder whether it is possible or not to use a subclass to solve my problem or if i have no choice but copying the main classes. Thanks in advance for your help.
Upvotes: 3
Views: 3725
Reputation: 15334
For the tab itself, if you are responsible for inflating the View, then you can use a custom TextView that modifies its content description based on its activated (or selected) state:
public class TabTextView extends TextView {
public TabTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public CharSequence getContentDescription() {
CharSequence contentDescription = super.getContentDescription();
return isActivated() ? appendSelectedTo(contentDescription) : contentDescription;
}
private String appendSelectedTo(CharSequence contentDescription) {
return getResources().getString(R.string.tab_selected, contentDescription);
}
}
where R.string.tab_selected
is <string name="tab_selected">%1$s selected</string>
This pre-supposes that you (or the library you're using) is marking the tab view with setActivated(true)/setSelected(true)
when selected (and all the other tabs with setActivated(false)/setSelected(false)
).
The simplest way to announce to the user that the content has changed is to add a ViewPager.OnPageChangeListener
that announces when the page changes:
viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
// TODO: format correctly with String resource to support translation
viewPager.announceForAccessibility("Showing " + viewPager.getAdapter().getPageTitle(position));
}
});
I know Android TalkBack users are used to the behavior without indication on what is clickable
There is (by default) an indication on elements that are clickable as @ChrisCM mentioned - TalkBack will append "Double Tap to Activate" (previously "Double Tap to Select") onto Views with a View.OnClickListener
attached.
You can modify the action that TalkBack reads aloud with an accessibility delegate by overriding the onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info)
method:
class TabAccessibilityDelegate extends AccessibilityDelegateCompat {
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
super.onInitializeAccessibilityNodeInfo(host, info);
info.addAction(
new AccessibilityNodeInfoCompat.AccessibilityActionCompat(
AccessibilityNodeInfoCompat.ACTION_CLICK,
"select tab"
)
);
}
}
and setting it on each of your tab Views:
ViewCompat.setAccessibilityDelegate(tabView, new TabAccessibilityDelegate());
such that now TalkBack will read: "<tab content description>... double tap to select tab"
.
Other ways to customise the usage hint is given in this answer.
Upvotes: 1
Reputation: 18870
This is actually pretty simple. What you want to do is create a subclass of PagerTabStrip. In this subclass, augment the propagation of accessibility events to add the information that you wish! Below is my implementation.
public class A11yPagerTabStrip extends PagerTabStrip {
public A11yPagerTabStrip(Context context) {
super(context);
}
public A11yPagerTabStrip(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Log.wtf(LOG_TAG, "onRequestSendAccessibilityEvent: " + event.toString());
final String textViewTitle = ((TextView) child).getText().toString();
final ViewPager viewPager = (ViewPager) this.getParent();
final int itemIndex = viewPager.getCurrentItem();
String title = viewPager.getAdapter().getPageTitle(itemIndex).toString();
if (textViewTitle.equalsIgnoreCase(title)) {
child.setContentDescription("Tab " + textViewTitle + "selected.");
} else {
child.setContentDescription("Tab " + textViewTitle + "not selected.");
}
return super.onRequestSendAccessibilityEvent(child, event);
}
}
Notice that I override the content description. In this way we don't change any of the visual representation of the application, just what talk back reads out.
NOTE: Talkback users are use to the "double tap to select" portion. I would leave this off, as I have done in my code.
Upvotes: 2