Android - 将TalkBack可访问性焦点设置为特定视图

Sky*_*r10 21 android accessibility talkback

启用TalkBack时,有没有办法将辅助功能焦点手动设置为特定视图?例如,当我的Activity启动时,我希望TalkBack自动关注某个Button(视图周围的黄色框)并阅读其内容描述.

到目前为止我尝试过的:

    myButton.setFocusable(true);
    myButton.setFocusableInTouchMode(true);
    myButton.requestFocus();
Run Code Online (Sandbox Code Playgroud)

requestFocus()似乎只是请求输入焦点而与可访问性焦点无关.我也尝试过:

    myButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
    myButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
    myButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
    myButton.announceForAccessibility("accessibility test");
    myButton.performAccessibilityAction(64, null); // Equivalent to ACTION_ACCESSIBILITY_FOCUS

    AccessibilityManager manager = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE);
    if (manager.isEnabled()) {
        AccessibilityEvent e = AccessibilityEvent.obtain();
        e.setSource(myButton);
        e.setEventType(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
        e.setClassName(getClass().getName());
        e.setPackageName(getPackageName());
        e.getText().add("another accessibility test");
        manager.sendAccessibilityEvent(e);
    }
Run Code Online (Sandbox Code Playgroud)

这似乎都不起作用.

Chr*_*sCM 35

免责声明:强制将活动负载集中在任何地方,但最重要的是总是(好吧,几乎永远不应该说),但实际上,就是不要这样做.它违反了各种WCAG 2.0法规,包括3.2.1和3.2.3,分别涉及可预测的导航和上下文变更.实际上,您可能实际上使您的应用程序更难以访问.

http://www.w3.org/TR/WCAG20/#consistent-behavior

免责声明.

您正在使用正确的函数调用.您需要做的就是:

myButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
Run Code Online (Sandbox Code Playgroud)

问题更可能是您尝试这样做的时间点.对话会在活动周期的稍后阶段将您的活动与自己的活动联系起来.以下解决方案说明了这个问题,老实说,我不确定有更好的方法可以做到这一点.我试过onPostResume,这是Android操作系统调用的最后一个回调,关于加载活动,但我仍然需要添加延迟.

@Override
protected void onPostResume() {
    super.onPostResume();

    Log.wtf(this.getClass().getSimpleName(), "onPostResume");

    Runnable task = new Runnable() {

        @Override
        public void run() {
            Button theButton = (Button)WelcomeScreen.this.findViewById(R.id.idButton);
            theButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
        }
    };

    final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();

    worker.schedule(task, 5, TimeUnit.SECONDS);

}
Run Code Online (Sandbox Code Playgroud)

您可以创建自定义视图.视图中的回调可以提供您执行此操作所需的逻辑,而不会出现竞争条件!如果我有时间,我可能会在以后更深入地研究它.

  • 虽然这种方法可能适用于当前版本的TalkBack,但我们给出的建议是**永远不要**尝试从应用程序手动放置辅助功能焦点.您将最终与TalkBack或用户战斗,这两者都不会提供良好的体验. (6认同)
  • 你应该用一些代码打开一个新问题.没有代码,很难猜出会出现什么问题. (3认同)
  • @ChrisCM您应该写一篇关于Android中的辅助功能的博客文章.我很想阅读最佳实践.比如,我们应该自动宣布工具栏标题还是让系统处理它,或者你上面提到的焦点.在我的情况下,我有一个EditText,它需要关注.我更喜欢使用Toolbar Title来使用它 (3认同)
  • 因此,免责声明;)。我想知道的是,为什么该事件不在受保护的空间中出现,仅适用于AccessibilityServices。您应该“绝不”做的事情,而且我同意这是每个WCag(以及常识TalkBack可用性)指南中的其中一项,似乎很适合此类。。。很好奇,虽然我得到了Google代表的关注! (2认同)

Gil*_*rra 8

最近我遇到了同样的问题。我创建了一个 Android 扩展函数来聚焦一个没有聚焦的视图,postDelayed就像上面的解决方案一样;

sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
Run Code Online (Sandbox Code Playgroud)

但我有另一种情况,它不起作用。但是,我让它与这个一起工作:

fun View.accessibilityFocus(): View {
    this.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null)
    this.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED)
    return this
}
Run Code Online (Sandbox Code Playgroud)

  • 对于遇到同样问题的其他人...我发现在 Android 10 上执行常规 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED) 无法与三星语音助手一起使用(奇怪的是 9 及以下罚款...)但是,此其他解决方案是唯一的可以在该设备上运行的东西。感谢吉尔伯托,非常感谢! (2认同)

and*_*seb 7

我遇到了同样的问题,因为为了实现一致的导航,我们希望选择新打开的页面的标题。问题是屏幕阅读器选择了页面左上角的第一个标题按钮,而不是标题。

我有一个myRootView用于整个视图的myTitleView变量和一个用于标题文本视图的变量。

ChrisCM 提出的将可访问性集中在正确视图上的解决方案肯定对我有帮助:

myTitleView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
Run Code Online (Sandbox Code Playgroud)

但是我仍然遇到了在应用程序启动时调用此代码无效的问题,因为屏幕阅读器尚未准备好,并且为“等待对讲可用”提出的等待 5 秒的解决方案不是我想要做的因为到那时,用户可能已经在使用界面,他们的选择会被自动对焦打断。

我注意到在打开应用程序时,左上角的标题按钮是通过可访问性系统地选择的,所以我写了一个类来监听该选择并在之后立即触发我自己的选择。

这是有问题的类的代码:

import android.view.View;
import android.view.View.AccessibilityDelegate;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public abstract class OnFirstAccessibilityFocusRunner extends AccessibilityDelegate implements Runnable {
    @NonNull
    private final View rootView;
    private boolean hasAlreadyRun = false;

    public OnFirstAccessibilityFocusRunner(@NonNull final View _rootView) {
        rootView = _rootView;
        init();
    }

    private void init() {
        rootView.setAccessibilityDelegate(this);
    }

    @Override
    public boolean onRequestSendAccessibilityEvent(@Nullable final ViewGroup host, @Nullable final View child,
        @Nullable final AccessibilityEvent event) {
        if (!hasAlreadyRun
            && event != null
            && event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
        ) {
            hasAlreadyRun = true;
            rootView.setAccessibilityDelegate(null);
            run();
        }
        return super.onRequestSendAccessibilityEvent(host, child, event);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我使用这样的代码(例如在 Activity 的 onPostResume 方法中):

@Override
protected void onPostResume() {
    new OnFirstAccessibilityFocusRunner(myRootView) {
        @Override
        public void run() {
            myTitleView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

我花了几个小时才弄清楚如何立即将焦点对准正确的视图,我希望这对其他人也有帮助!