简单使用 Accessibility 及 Android 适配 TalkBack,实现适老化和无障碍

简单使用 Accessibility 及 Android 适配 TalkBack,实现适老化和无障碍

前言:工信部发布的互联网应用适老化及无障碍改造的通知,app 需要进行改造,以提高老年人或者视障人士在使用 app 过程的便捷性,改造的内容包括但不限于

1、UI 界面更简单、整洁(界面元素不能过于复杂,字体字号需要偏大、清晰)

2、页面焦点导航的适配

3、页面元素需要适配 TalkBack 朗读

4、搭建无障碍服务 service

关于界面文字字号大小的选择的,我前面发过文章介绍过方案,今天主要讲讲 android 中 Accessibility 相关使用以及其他一些简单的改造。

一、给控件加上 contentDescription 属性和正确的朗读文案。

(1)对于 TextView / Button,TalkBack 会读出设置的 text 属性的文本,一般情况不需要特殊适配

(2)对于 EditText ,TalkBack 会读 hint 属性设置的文字,输入内容后会播报输入后的问题

(3)对于其他没有 text 属性的控件

1、通过 layout 文件里面设置 contentDescription 属性设置文本

2、通过代码中调用 view.setContentDescription() 方法设置文本

android:layout_width="@dimen/dp_190"

android:layout_height="@dimen/dp_190"

android:layout_alignParentRight="true"

android:layout_alignParentTop="true"

android:src="@drawable/bg_login_watermark"

android:contentDescription="@string/love_version_read_Img_Water_mark"/>

iv_back.setContentDescription(getString(R.string.love_version_read_Img_Back));

二、启用焦点导航

在使用 TalkBack 测试的过程中,发现有些比较复杂的布局内容子控件点击不到,因此也无法播报,这就需要我们对页面的焦点视图做好控制。

(1)如果我们需要某个控件是可以在 TalkBack 模式下可点击并播报的话,需要给控件设置 android:focusable = "true",或者在代码中调用 setFocusable()。否则的话焦点会在整个父布局,导致某个区域块点击会顺序播报整块区域的内容。

(2)设置焦点顺序。

通过 android:nextFocusDown, android:nextFocusLeft, android:nextFocusRight, android:nextFocusUp 或者运行时通过 setNextFocusDownId(), setNextFocusrightId() 等方法动态控制用户界面组件的聚焦顺序。以确保用户在使用手势、虚拟键导航时可以有较好的体验。

(3)talkback 开启不获取焦点。

如果你希望该区域(ViewGroup、View)不播报,通过下面代码来设置。

android:impoartantForAccessibility="no"/>

三、给控件加上正确的播报类型

一般的,我们需要让视障人士清楚当前点击的区域是什么,比如我们的按钮、图片等等,开启 talkback 的情况下,通过设置类型来让系统在控件获取焦点时播报。

例如:下面的设置,系统将会播报“按钮,(设置好的 contentDescription)”

ViewCompat.setAccessibilityDelegate(tv_url, new AccessibilityDelegateCompat(){

@Override

public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {

super.onInitializeAccessibilityNodeInfo(host, info);

info.setClassName(Button.class.getName());

}

});

四、拦截自定义视图的播报。

项目中,难免会用到一些自定义的组件,比如 banner、手势滑动组件等等。例如在项目中我自已写的一个画廊效果的滑动窗,在开启 talkback 模式之后,滑动会播报 “多视图页面,第一项,第二项”之类的,我们当然不希望用户听到这些,即便是在加了 contentDescription 之后也依旧会存在,这个时候,通过重写 onRequestSendAccessibility() 方法,你可以直接 return false,即不处理该事件,就不会播报上述的“多视图页面”。

@Override

public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {

return false;

}

五、拦截页面的播报。

开启 talkback 模式下,在 Activity 或者 Fragment中,进入一个新的页面时,往往会触发系统一些播报。我遇到的情况是,在首页有广告 banner 的情况下,进入首页系统就会播报“第 2000 项目,共 两千零几项”这种。

解决方法:

@Override

public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {

event.getText().add("");

return super.dispatchPopulateAccessibilityEvent(event);

}

六、主动播报。

有些场景下,需要对用户的滑动做出反馈,比如 banner,滑动选择窗口。当用户滑动到某一项,但是还未点击的时候,我们可以做出反馈,通过 announceForAccessibility() 方法 及时反馈当前的选中项。

tv_url.announceForAccessibility("您当前选中的是。。。");

七、判断当前是否开启 talkback 模式。

有些场景,需要判断手机是否开启 talkback 模式,以此来进行一些特殊的逻辑处理。比如一些app会有人脸识别、身份证识别的功能。在talkback 模式下,对当前的识别状态进行播报反馈,提升用户的体验。比如人脸识别,脸太靠前,或者不居中等情况,一般都只有文字提示,我们判断系统是否开启 talkback,将文字提示进行播报。

(1)通过 AccessibilityManager 的 isEnabled() 方法。

AccessibilityManager accessibilityManager;

accessibilityManager = (AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE);

boolean isTalkBackEnabled = accessibilityManager.isEnabled();

但是这个方法有个问题,就是不够准确,测试的时候发现,有的手机单用这个方法会有误判的情况,就是手机明明没有开启 talkback,但还是返回了 true。后面了解到是有些 app ,会开启相关的 AccessibilityService ,比如爱奇艺,所以在安装了爱奇艺app的手机,isTalkBackEnabled 就返回了 true。影响了我们的判断结果。所以我们需要再加一个判断。

(2)直接上代码了

private static boolean isTalkBackEnable(Context context) {

Intent screenReaderIntent = new Intent(SCREEN_READER_INTENT_ACTION);

screenReaderIntent.addCategory(SCREEN_READER_INTENT_CATEGORY);

List screenReaders = context.getPackageManager().queryIntentServices(screenReaderIntent, 0);

if (screenReaders == null || screenReaders.size() <= 0) {

return false;

}

boolean hasActiveScreenReader = false;

if (Build.VERSION.SDK_INT <= 15) {

ContentResolver cr = context.getContentResolver();

Cursor cursor = null;

int status = 0;

for (ResolveInfo screenReader : screenReaders) {

cursor = cr.query(Uri.parse("content://" + screenReader.serviceInfo.packageName

+ ".providers.StatusProvider"), null, null, null, null);

if (cursor != null && cursor.moveToFirst()) {

status = cursor.getInt(0);

cursor.close();

// 状态1为开启状态,直接返回true即可

if (status == 1) {

return true;

}

}

}

} else if (Build.VERSION.SDK_INT >= 26) {

// 高版本可以直接判断服务是否处于开启状态

for (ResolveInfo screenReader : screenReaders) {

hasActiveScreenReader |= isAccessibilitySettingsOn(context, screenReader.serviceInfo.packageName + "/" + screenReader.serviceInfo.name);

}

} else {

// 判断正在运行的Service里有没有上述存在的Service

List runningServices = new ArrayList();

android.app.ActivityManager manager = (android.app.ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

for (android.app.ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {

runningServices.add(service.service.getPackageName());

}

for (ResolveInfo screenReader : screenReaders) {

if (runningServices.contains(screenReader.serviceInfo.packageName)) {

hasActiveScreenReader |= true;

}

}

}

return hasActiveScreenReader;

}

以上两点同时使用就可以准确判断是否开启 talkback 了。第二点是参考下面这篇博客的,感谢老哥哈,一开始我只用了第一种,在测试机就没问题,在自己手机就不行,后面看完才知道是我手机安装了爱奇艺的原因。

参考的博客地址:Android完美判断是否开启无障碍服务功能 - 简书

这是一条分隔线

本次 APP 适老化改造用到的内容大概就这么多,后面如果有继续优化再接着补充。

猜你喜欢 💖

直播软件服务费详解:了解其构成与作用
beat365官方网址

直播软件服务费详解:了解其构成与作用

📅 08-24 👁️ 6369
两台电脑联机的步骤分享 蒲公英如何轻松实现电脑联机?
365bet网上足球比赛

两台电脑联机的步骤分享 蒲公英如何轻松实现电脑联机?

📅 09-16 👁️ 4167
领航机油怎么样,领航机油和壳牌哪个好
beat365体育下载

领航机油怎么样,领航机油和壳牌哪个好

📅 08-10 👁️ 9093