The problem
When we set a description for a control, it looks like this:
xxxView.setContentDescription("xxx");
Copy the code
However, when you set this to EditText, it doesn’t work. Why is that?
Search EditText and its immediate parent TextView. Instead of overwriting the setContentDescription method, it should be getXXX, not setXXX.
Sure enough, TextView found:
/**
* Returns the text that should be exposed to accessibility services.
* <p>
* This approximates what is displayed visually. If the user has specified
* that accessibility services should speak passwords, this method will
* bypass any password transformation method and return unobscured text.
*
* @return the text that should be exposed to accessibility services, may
* be {@code null} if no text is set
*/
@Nullable
@UnsupportedAppUsage
private CharSequence getTextForAccessibility(a) {
// If the text is empty, we must be showing the hint text.
if (TextUtils.isEmpty(mText)) {
return mHint;
}
// Otherwise, return whatever text is being displayed.
return TextUtils.trimToParcelableSize(mTransformed);
}
Copy the code
So EditText reads only the Hint text, not the contentDescription, when it gets the accessible focus. There is nothing wrong with this design: the editable control should read the hint when there is no input.
However, some custom controls look like this:
The label is drawn on the customized View, and Talkback cannot recognize it without special treatment. The best experience is to read the label on the left side as well (for example, “train number, example: G1”). What can be done?
To solve
Obviously, you can’t just change hint, or else the UI will display incorrectly.
Try one: can I read a string of text myself while getting focus
We know that it can be done by:
xxxView.announceForAccessibility("xxx");
Copy the code
But there isn’t a setOnFocusChangeListener method for listening specifically to focus on accessibility, so it’s tricky.
Read the fucking code
There are also some key approaches to accessibility development that Talkback accessibility AIDS will eventually trigger:
xxxView.requestAccessibilityFocus(); // Get the accessibility focus, automatically read the set description
xxxView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); // The effect is similar to the former, and the former also calls this method last
Copy the code
After further investigation, the following information can be traced:
public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {... onInitializeAccessibilityEvent(event);// Only a subset of accessibility events populates text content.
if((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) ! =0) {
dispatchPopulateAccessibilityEvent(event);
}
// In the beginning we called #isShown(), so we know that getParent() is not null.
ViewParent parent = getParent();
if(parent ! =null) {
getParent().requestSendAccessibilityEvent(this, event); }}Copy the code
Made it clear that this onInitializeAccessibilityEvent source comments written is triggered when controls access to the barrier-free event, but in the event parameter what we seem can’t do it.
We found that in the Textview onInitializeAccessibilityNodeInfoInternal and neighbouring onInitializeAccessibilityEventInternal has an internal method:
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
final booleanisPassword = hasPasswordTransformationMethod(); info.setPassword(isPassword); info.setText(getTextForAccessibility()); info.setHintText(mHint); info.setShowingHintText(isShowingHint()); . }Copy the code
This info. The setText (getTextForAccessibility ()); That’s the key. It’s actually the text that’s read out at the end.
Public methods onInitializeAccessibilityNodeInfo annotation also shows: Initializes an {@link AccessibilityNodeInfo} with information about this view. This method initializes some of the View’s accessibility basic information.
Final solution:
Override methods in a custom EditText class to override the text so that it is read as desired:
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
// For EditText, the system-accessible read only hint overwrites the custom content through the node info
info.setText("xxx" + getHint());
}
Copy the code
Info.settext (getContentDescription())); It’s much more convenient.