Android Acccessibility: How do I change the text r

2019-04-28 16:50发布

问题:

By default, the Accessibility Services will read out the following for an EditText view

  • If the EditText has a value entered = it will read out that value
  • If there is not value entered = it will read out the "hint"

I want it to read out something completely different in both cases.

My xml snippet is

<EditText
    android:id="@+id/my_edit_text"
    android:layout_height="wrap_content"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:editable="false"
    android:focusable="true"
    android:hint="my hint text"/>

I have to support API 14 and onwards.

I do not want to go to the trouble of extending EditText for this one single case, therefore I am using am AccessibilityDelegate.

mEditTextView.setAccessibilityDelegate(accessibilityDelegate);

From the documentation I understand that in my delegate I only have to overwrite those methods in the delegate for which I would like to change the behaviour. All other methods will default to the View's implementation.

http://developer.android.com/reference/android/view/View.AccessibilityDelegate.html http://developer.android.com/reference/android/view/View.html

The doc for "onPopulateAccessibilityEvent" says : "Gives a chance to the host View to populate the accessibility event with its text content." The doc for "dispatchPopulateAccessibilityEvent" says : "Dispatches an AccessibilityEvent to the host View first and then to its children for adding their text content to the event." and that the default behaviour is to call "onPopulateAccessibilityEvent" for the view itself and then "dispatchPopulateAccessibilityEvent" on all its children

http://developer.android.com/guide/topics/ui/accessibility/apps.html

This doc says under "onPopulateAccessibilityEvent" "*If your implementation of this event completely overrides the output text without allowing other parts of your layout to modify its content, then do not call the super implementation of this method in your code."

Therefore my delegate is the following

View.AccessibilityDelegate accessibilityDelegate = new View.AccessibilityDelegate() {
    @Override
    public void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
        event.getText().add("Apples");
    }

};

Why when I use the keyboard to navigate to or use the screen to tap on the EditText view it is still reading "my hint text" and not "Apples"?

If I use a debugger, I see that before I set the event text, the text is empty and after I set it, it is "Apples" yet the TalkBack still reads out the hint.


Weirdly if I overwrite "onInitializeAccessibilityNodeInfo" and send an event with my desired text, then this desired text gets read out (see code snippet below). But this seems wrong to me as the "onInitializeAccessibilityNodeInfo" is reacting to the EditText's event but then just raising a new one.

@Override  
public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfo info){  
    super.onInitializeAccessibilityNodeInfo(v, info);      
    ...   
    final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);  
    event.getText().add("Pears");  
    event.setClassName(className);  
    event.setPackageName(packageName);  
    ...     
    v.getParent().requestSendAccessibilityEvent(v, event);  
}

回答1:

This sounds very similar to a problem I previously encountered: Android: How to eliminate spoken text from AccessibilityEvents when extending SeekBar?

Have you tried (as a test) clearing the hint text in onPopulateAccessibilityEvent, rather than just adding the 'Apples' text? I seem to remember that my empirical results did not match the Android documentation, particularly for Android OS prior to API 14.



回答2:

We can change the text read out loud of EditText view by doing the following:

View.AccessibilityDelegate accessibilityDelegate = new View.AccessibilityDelegate() {
    @Override
    public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfo(v, info);
        info.setText("some customized text")
    }  
};

and then set this delegate to the EditText View.