Welcome to pay attention to the wechat public account “Conveniently Record Technical Team”, check out more technical articles of conveniently Record team. Reprint please indicate the source In this paper, the author: melody tang The original link: mp.weixin.qq.com/s/YckeGC_ZU…
Keep track of Android accessibility practices
preface
According to statistics, there are currently more than 17 million visually impaired people in China, meaning that on average, one in 81 visually impaired people may encounter difficulties in using Internet services. At present, Jiji has 300 million registered users. In order to make financial services benefit every user, to help the visually impaired easily conduct bookkeeping, investment and learn financial intelligence knowledge, and to enable them to access and use information equally, conveniently and barrier-free, we have made barrier-free transformation and optimization of Jiji Android.
Accessibility Guide
The accessibility of Android products is mainly aimed at people with visual impairments. After the accessibility service (such as TalkBack) is enabled in the auxiliary functions of the device, it can read the text information on the screen and convert it into voice prompts to achieve information accessibility.
Specification details
- All views should be labeled with the contentDescription property
- Text labels should be meaningful
- Decorative UI elements need to be stripped of labels and focus
- The EditText requires the hint attribute to set the label
- The size of touch targets must be at least 48 x 48dp, and the distance between touch targets must be at least 8dp
- You should group together related elements that have the same response
- Focus switch order should follow visual order, from left to right, top to bottom
- More complex pages should be grouped and focused with less granularity
- Custom controls need to be barrier-free
WCAG 2.0 four principles
- Perceptive: Information and user interface components must be presented to the user in a perceptive manner.
- Operable: User interface components and navigation must be operable.
- Comprehensible: Information and user interface actions must be comprehensible.
- Robustness: The content must be robust enough to be credibly interpreted by a wide variety of user agents, including assistive technologies.
Enabling Accessibility Services
- Download and install TalkBack (some systems come with it), which reads text messages from the screen
- Make sure you have a text-to-speech (TTS) output engine, which usually comes with your phone. You can also download text notes
- Go to Settings -> Accessibility (or advanced options) -> Find the TalkBack service and enable it
When the green area and voice prompt appear, it indicates that the user enters the barrier-free mode. If a View is selected and a text message is displayed, it indicates that the View has barrier-free functions.
The operation mode has changed
- Click to select a View with focus (green area)
- Double click is equivalent to clicking in normal mode (start, enter, etc.)
- Slide, need two fingers up, down, left, right
Practical instance
1. Add labels to UI elements
Find all valid elements in the interface and set the text message.
Simple code examples:
// XML
<ImageButton
...
android:contentDescription="@string/share" />
Copy the code
// Private voidupdateImageButton() {
if (mediaCurrentlyPlaying) {
playPauseImageView.setContentDescription(getString(R.string.pause));
} else{ playPauseImageView.setContentDescription(getString(R.string.play)); }}Copy the code
1.1 Adding Labels Correctly
- If the contentDescription property is empty, the accessibility service will retrieve the text message from the Text property as a voice prompt.
- EditText, which sets the value of the hint property
- Other controls (such as ImageView, ImageButton) need to set the contentDescription value
1.2 Provide clear and meaningful label text
- Strive for precision and simplicity
- Avoid including type and state in description text
- Indicate element functionality rather than describing ICONS
- If the status or function changes, the label must be changed accordingly
2. Change the status of non-standard components
rootView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
info.setCheckable(true); info.setChecked(itemData.isSelected()); }});Copy the code
3. Focus processing
Some interfaces contain decorative elements that need to be removed from focus. For example: memorizing more interface spacing blocks.
Examples of code to remove focus:
android:focusable="false"
android:focusableInTouchMode="false"
android:importantForAccessibility="no"
Copy the code
4. Transformation of custom View
4.1 The scroll wheel in the following figure cannot be used in barrier-free mode if it is not processed.
2. In the callback function selected by the scroll wheel Item, set the View’s contentDescription property to send barrier-free events.
// To prevent high frequency, do delay processing private voidsendAccessibilityViewSelectedEvent() {
postDelayed(new Runnable() {
@Override
public void run() {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
}, 200L);
}
Copy the code
3. The overloading onPopulateAccessibilityEvent method, add a description text
@Override @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void onPopulateAccessibilityEvent(AccessibilityEvent event) { super.onPopulateAccessibilityEvent(event); int eventType = event.getEventType();if (eventType == AccessibilityEvent.TYPE_VIEW_SELECTED
|| eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
if(viewAdapter ! = null) { event.getText().add(viewAdapter.getItemContentDes(currentItem)); event.setItemCount(viewAdapter.getItemsCount()); event.setCurrentItemIndex(currentItem); }}}Copy the code
4.2 Transformation of gesture panel
It’s just a block before it’s processed, and it doesn’t react when you slide.
A better way to do this is with ExploreByTouchHelper. (Mainly referring to the Android 5.1 system source code LockPatternView class barrier-free implementation.) The following code implementation is given: 1. Write the corresponding ExploreByTouchHelper class and overload the six methods
private final class PatternExploreByTouchHelper extends ExploreByTouchHelper { private Rect mTempRect = new Rect(); private HashMap<Integer, VirtualViewContainer> mItems = new HashMap<>(); private static final int VIRTUAL_BASE_VIEW_ID = 1; /** * Gesture panel has 9 points, each point as a virtual node, according to the x,y coordinates to obtain the corresponding virtual node number (this int value by their own agreement) * @returnOther return ExploreByTouchHelper. INVALID_ID * / @ Override protected int getVirtualViewAt (float x, float y) {
final int rowHit = getRowHit(y);
if (rowHit < 0) {
return ExploreByTouchHelper.INVALID_ID;
}
final int columnHit = getColumnHit(x);
if (columnHit < 0) {
return ExploreByTouchHelper.INVALID_ID;
}
boolean dotAvailable = mPatternDrawLookup[rowHit][columnHit];
int dotId = (rowHit * 3 + columnHit) + VIRTUAL_BASE_VIEW_ID;
int view = dotAvailable ? dotId : ExploreByTouchHelper.INVALID_ID;
returnview; } /** * the name of the method is a bit strange. It is used to insert the number of the virtual node into the List. 1 to 9 * @override protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {if(! mPatternInProgress) {return;
}
for (int i = VIRTUAL_BASE_VIEW_ID; i < VIRTUAL_BASE_VIEW_ID + 9; i++) {
if(! mItems.containsKey(i)) { VirtualViewContainer item = new VirtualViewContainer(getTextForVirtualView(i)); mItems.put(i, item); } virtualViewIds.add(i); }} /** * populate each virtual node with events, Which nine points of the gesture panel set description text * / @ Override protected void onPopulateEventForVirtualView (int virtualViewId, AccessibilityEvent event) {if(mItems.containsKey(virtualViewId)) { CharSequence contentDescription = mItems.get(virtualViewId).description; event.getText().add(contentDescription); }} /** * fill the host View with events, The gesture panel set up to describe the text * / @ Override public void onPopulateAccessibilityEvent (View the host, AccessibilityEvent event) { super.onPopulateAccessibilityEvent(host, event);if(! mPatternInProgress) { CharSequence contentDescription = getContext().getText(R.string.lock_pattern_area); event.setContentDescription(contentDescription); }} /** * Set the description text and border for the virtualView ** border refers to the selected block boundary in barrierfree mode * @param virtualViewId * @param node */ @override protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat node) { node.setText(getTextForVirtualView(virtualViewId)); node.setContentDescription(getTextForVirtualView(virtualViewId));if (mPatternInProgress) {
node.setFocusable(true);
if(isClickable(virtualViewId)) { node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK); node.setClickable(isClickable(virtualViewId)); } } final Rect bounds = getBoundsForVirtualView(virtualViewId); node.setBoundsInParent(bounds); } /** * provides interaction, Triggered the callback to redraw the control * / @ Override protected Boolean onPerformActionForVirtualView (int virtualViewId, int the action, Bundle arguments) { switch (action) {case AccessibilityNodeInfo.ACTION_CLICK:
return onItemClicked(virtualViewId);
default:
break;
}
return false;
}
// ...
}
Copy the code
2. Set the barrier-free proxy in the constructor
public LockPatternView(Context context) {
// something else/ /... / / barrier-free agent mPatternTouchHelper = new PatternExploreByTouchHelper (this); ViewCompat.setAccessibilityDelegate(this, mPatternTouchHelper); }Copy the code
3. Implement onHoverEvent() and dispatchHoverEvent() in LockPatternView
@Override
public boolean onHoverEvent(MotionEvent event) {
final int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_HOVER_ENTER:
event.setAction(MotionEvent.ACTION_DOWN);
break;
case MotionEvent.ACTION_HOVER_MOVE:
event.setAction(MotionEvent.ACTION_MOVE);
break;
case MotionEvent.ACTION_HOVER_EXIT:
event.setAction(MotionEvent.ACTION_UP);
break;
case MotionEvent.ACTION_CANCEL:
event.setAction(MotionEvent.ACTION_CANCEL);
}
onTouchEvent(event);
event.setAction(action);
returnsuper.onHoverEvent(event); } @Override protected boolean dispatchHoverEvent(MotionEvent event) { boolean handled = super.dispatchHoverEvent(event); handled |= mPatternTouchHelper.dispatchHoverEvent(event);return handled;
}
Copy the code
AnnounceForAccessibility () is called in the callback function for gesture states (completed, interrupted, etc.) to inform the user.
conclusion
In the realization of barrier-free at the same time, also solved the problem of UI automation test of custom View. Accessibility needs constant updating, iteration and optimization. The team also developed accessibility coding specifications, which were included in code review points, to ensure that the product continued to provide good accessibility.
The resources
Android官方无障碍指南
Android无障碍宝典
WCAG 2.0