手游网 手游攻略 软件教程 抖音Android无障碍开发知识总结

抖音Android无障碍开发知识总结

时间:2024-12-30 14:57:49 来源:其他 浏览:0

无障碍模式下的使用方法

抖音的无障碍功能主要是通过开启Google TalkBack(或第三方屏幕朗读)功能来实现,当用户触摸屏幕时读出所选区域的内容,以便视障人士可以根据阅读的内容获取他们当前的信息。操作区域显示信息,从而改善视障人士的使用和交互体验。

常用操作手势:

浏览视图: 点击视图: 双击并向某个方向滑动: 两根手指向所需方向滑动可依次浏览页面: 一根手指左右滑动,让研发同学对辅助功能有更全面的了解。方便研发同学开发无障碍功能。

无障碍功能实现原理

系统结构

无障碍功能的实现需要以下三部分的支持:辅助App(如TalkBack)、辅助App(用户使用的App,如抖音头条等)和系统服务AccessibilityManagerService。这三者之间的关系如下图所示:

从上图可以看出,上述过程主要涉及到三个进程的通信。辅助应用程序和被辅助应用程序不需要直接与被辅助应用程序通信。相反,它们通过SystemServer 进行通信。这个过程主要涉及到四个aidl接口:

当辅助应用-SystemServer(IAccessibilityManager.aidl)产生触摸事件时,会通过该接口将辅助功能事件发送给SystemServer进程的AccessibilityManagerService。

SystemServer-辅助应用(IAccessibilityServiceClient.aidl) 当SystemServer收到辅助应用发送的无障碍事件时,会通过该接口将该事件传递给辅助应用(如TalkBack)进行处理。

辅助应用-SystemServer(IAccessibilityServiceConnection.aidl) 系统服务器辅助应用(IAccessibilityInteractionConnection.aidl) 当需要辅助应用的某个View的信息时,可以通过这两个接口的findAccessibilityNodeInfosByViewId方法来实现。

无障碍事件传递流程

当用户触摸屏幕时,触摸事件会通过以下过程传递到被触摸的View:

1.无障碍模式下的事件转换

在FLAG_FEATURE_TOUCH_EXPLORATION 模式下创建TouchExplorer 对象。 AccessibilityInputFilter继承InputFilter,过滤输入事件,并通过与TouchExplorer配合实现TalkBack模式下的触摸浏览手势。 TouchExplorer负责将普通触摸事件转换为触摸浏览手势,例如将MotionEvent.ACTION_DOWN事件转换为MotionEvent.ACTION_HOVER_ENTER(悬停事件)。因此,当TalkBack开启时,用户点击View时App会执行ACTION_HOVER_ENTER事件,双击View时App会执行ACTION_DOWN事件。

2.触摸事件到 Activity 的传递过程

在Android中,消息机制就是handler机制。通过将消息封装成Message,并将消息发送到handler所在的MessageQueue中,Looper不断调用MessageQueue的next方法进行消息处理。

当用户触摸屏幕上的View 时,处理程序将按如下方式处理收到的消息:

这里需要重点关注View的dispatchPointerEvent()方法:

公共最终布尔dispatchPointerEvent(MotionEvent事件){如果(event.isTouchEvent()){返回dispatchTouchEvent(事件); } else { 返回dispatchGenericMotionEvent(事件); }} 在这个方法中,对事件进行了判断。如果是touchEvent,则调用dispatchTouchEvent()方法,否则调用dispatchGenericMotionEvent()方法。判断是否为触摸事件的逻辑如下:

bool MotionEvent:isTouchEvent(int32_t source, int32_t action) { if (source AINPUT_SOURCE_CLASS_POINTER) { //特别排除HOVER_MOVE 和SCROLL。开关(操作AMOTION_EVENT_ACTION_MASK){ 案例AMOTION_EVENT_ACTION_DOWN: 案例AMOTION_EVENT_ACTION_MOVE: 案例AMOTION_EVENT_ACTION_UP: 案例AMOTION_EVENT_ACTION_POINTER_DOWN: 案例AMOTION_EVENT_ACTION_POINTER_UP: 案例AMOTION_EVENT_ACTION_CANCEL第:章AMOTION_EVENT_ACTION_OUTSIDE:返回true; } } return false;}满足上述情况的事件就是TouchEvent。

首先我们看一下dispatchPointerEvent方法中对TouchEvent事件的处理。进入DecorView的dispatchTouchEvent()方法:

@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) { Final Window.Callback cb=mWindow.getCallback(); return cb !=null !mWindow.isDestroyed() mFeatureId 0 ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);} 在此方法中,mWindow 是与Activity 关联的PhoneWindow 对象。由于DecoView是由PhoneWindow创建的,并且通过setWindow()方法,DecoView对象保存了对PhoneWindow对象的引用。通过getCallback() 方法,得到了一个实现了Window.Callback 的对象,而Activity 也实现了这个接口,所以当调用cb.dispatchTouchEvent(ev) 时,实际上调用的是Activity 中的dispatchTouchEvent()方法。

同样,在dispatchGenericMotionEvent()方法中,也有类似的代码逻辑:

@Overridepublic boolean dispatchGenericMotionEvent(MotionEvent ev) { Final Window.Callback cb=mWindow.getCallback(); return cb !=null !mWindow.isDestroyed() mFeatureId 0 ? cb.dispatchGenericMotionEvent(ev) : super.dispatchGenericMotionEvent(ev);} 该方法实际上调用了Activity的dispatchGenericMotionEvent()方法来进行后续事件的分发和处理。至此,事件已经传递给了Activity,Activity进一步分发事件。

3.触摸事件传递到具体 View 的过程

在研究无障碍模式下的事件传递流程之前,我们先回顾一下普通模式下的事件传递机制:

3.1 普通模式的事件分发

3.1.1 正常模式下的事件分发按键方法

当MotionEvent产生时,系统需要将该事件传递给特定的视图。这个传递过程就是事件分发过程。分发过程依赖于以下三个重要方法:

public boolean dispatchTouchEvent(MotionEvent ev) 该方法用于分发事件。该方法的返回值取决于当前View的onTouchEvent()方法和子View的dispatchTouchEvent()方法的影响。

public boolean onInterceptTouchEvent(MotionEvent ev) 是ViewGroup独有的方法,用于判断是否拦截事件。

在dispatchTouchEvent()方法中调用public boolean onTouchEvent(MotionEvent event)来处理点击事件。

3.1.2 普通模式下的事件分发

整个分发过程可以用下面的流程图来表示:

抖音Android无障碍开发知识总结

3.2 无障碍模式下的事件分发

无障碍模式下的事件分发与正常模式下的事件分发有许多相似之处:

3.2.1 无障碍模式下的事件分发按键方法:

与普通事件触摸事件的分发类似,accessibility事件触发事件的分发也有三个重要的方法:

protected boolean dispatchHoverEvent(MotionEvent event) 该方法用于分发事件。该方法的返回值取决于当前View的onHoverEvent()方法和子View的dispatchHoverEvent()方法的影响。

public boolean onInterceptHoverEvent(MotionEvent event) 是ViewGroup独有的方法,用于判断是否拦截事件。

在dispatchHoverEvent()方法中调用public boolean onHoverEvent(MotionEvent event)来处理悬停事件。

3.2.2 无障碍模式下的事件分发

当用户处于辅助功能模式并且用户点击屏幕时,会调用dispatchPointerEvent方法中的dispatchGenericMotionEvent方法:

公共最终布尔dispatchPointerEvent(MotionEvent事件){如果(event.isTouchEvent()){返回dispatchTouchEvent(事件); } else { 返回dispatchGenericMotionEvent(事件); }}其实就是调用了Activity的dispatchGenericMotionEvent()方法,Activity接收到事件后,会传递给PhoneWindow,然后传递给DecorView。 DecorView会调用View的dispatchGenericMotionEvent()方法:

公共布尔dispatchGenericMotionEvent(MotionEvent事件){·最终int源=event.getSource(); if ((source InputDevice.SOURCE_CLASS_POINTER) !=0) { Final int action=event.getAction(); //判断事件类型是否属于Hover,调用dispatch方法开始分发if (action==MotionEvent.ACTION_HOVER_ENTER || action==MotionEvent.ACTION_HOVER_MOVE || action==MotionEvent.ACTION_HOVER_EXIT) { if (dispatchHoverEvent(event) ) { 返回真; } } . return false;} 该方法中,如果判断事件是HoverEvent,则调用ViewGroup的dispatchHoverEvent()方法开始事件分发。

如果ViewGroup 的onInterceptHoverEvent() 方法返回true,则意味着它将拦截当前事件并将其留给自己处理。否则返回false,表示不会拦截当前事件,继续将当前事件传递给子View。子View会调用自己的dispatchHoverEvent()方法,以此类推,直到事件最终处理完毕。

在事件处理阶段,View/ViewGroup首先会判断是否设置了OnHoverListener,并判断其onHover方法的返回值是否为true。如果返回值为true,则不会调用onHoverEvent(),否则将调用onHoverEvent()方法。处理事件。

整个处理过程可以用下面的流程图来表示:

在onHoverEvent() 方法中,会调用sendAccessibilityHoverEvent() 方法,该方法随后会调用以下方法:

sendAccessibilityEventsendAccessibilityEventUncheckedonInitializeAccessibilityEventdispatchPopulateAccessibilityEventonPopulateAccessibilityEventonRequestSendAccessibilityEvent(仅在ViewGroup中默认实现) 以上6个方法是自定义View时可以重写以适应辅助功能模式的方法。您可以重写View的这些方法或者实现View.AccessibilityDelegate来解决一些特殊场景下的TalkBack问题。报告问题。

sendAccessibilityEventUnchecked 方法将向上传递到ViewRootImpl 的requestSendAccessibilityEvent 方法。这可以从堆栈信息中确认:

然后accessibility事件会通过AccessibilityManager的sendAccessibilityEvent方法跨进程调用system_process进程的AccessibilityManagerService,并将AccessibilityEvent事件传递给TalkBack的TalkBackService。

4.无障碍事件的执行流程

本节主要分析从TalkBack发出无障碍事件到辅助应用在屏幕上绘制绿框的过程。

TalkBack向被辅助APP发送无障碍事件时,需要system_process进程作为中转,对应的接口为IAccessibilityServiceConnection.aidl和IAccessibilityInteractionConnection.aidl。传输完成后,最终会调用被触摸的View的performAccessibilityAction方法。如果没有委托,将执行performAccessibilityActionInternal 方法。在该方法中,如果是ACTION_ACCESSIBILITY_FOCUS事件,则会执行requestAccessibilityFocus方法:

该方法执行两个关键操作:

调用ViewRootImpl的setAccessibilityFocus方法将自身设置为焦点,然后调用invalidate()触发重绘操作。 ViewRootImpl会在onPostDraw方法中执行drawAccessibilityFocusedDrawableIfNeeded来绘制绿框。

调用sendAccessibilityEvent方法发送TYPE_VIEW_ACCESSIBILITY_FOCUSED事件。对讲接收到该事件后,会调用阅读引擎TTS读出View的内容,实现无障碍模式下触摸区域内容的广播。

无障碍功能实现实例

案例1:在辅助功能模式下单击视图会报告“Untagged” 解决方案:在视图的android:contentDescription 属性上设置要报告的字符串。

情况2:焦点过多,需要移除多余的焦点或者某个View需要能够广播。解决方案:将不需要广播的View的android:importantForAccessibility属性设置为no,将需要广播的View的该属性设置为yes。

情况3:在辅助模式下,点击上层页面仍然可以选择下层View解决方案:将下层根View的android:importantForAccessibility属性设置为'noHideDesendants'

情况4:使用的自定义Toast不广播内容。解决方案:当自定义Toast显示时,主动发送AccessibilityEvent事件。

mText.postDelayed(new Runnable() { @Override public void run() { mText.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); }}, 1);设置延迟是为了避免无效的问题。

案例5:设置自定义View的播放内容。解决方案:重写View的onPopulateAccessibilityEvent()方法。

示例:设置自定义查看开/关状态(on/off)广播内容。

@Overridepublic void onPopulateAccessibilityEvent(AccessibilityEvent event) { super.onPopulateAccessibilityEvent(event);最终CharSequence 文本=isChecked() ? '已开放' : '已关闭'; if (text !=null) { event.getText().add(text); }}案例6:设置自定义View上报的控件类型和选中状态解决方案:使用AccessibilityDelegate

ViewCompat.setAccessibilityDelegate(targetView, new AccessibilityDelegateCompat() { @Override public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { super.onInitializeAccessibilityNodeInfo(host, info); info.setRoleDescription('label type');//设置广播标签类型info.setCheckable(true); info.setChecked(checked);//设置广播的选中状态}});

加入我们

欢迎加入抖音关系与服务团队。我们专注于抖音多个核心业务场景的实施和迭代,在业务、架构、技术等方面的投入,期待您的加入!

用户评论

在哪跌倒こ就在哪躺下

我在尝试学习新技能时发现这款游戏帮助我更好地理解了无障碍开发的概念。

    有14位网友表示赞同!

无关风月

这是一款让我能快速掌握Android无障碍功能的强大工具,推荐给需要入门的朋友。

    有6位网友表示赞同!

|赤;焰﹏゛

我刚刚开始接触无障碍编程,这款安卓游戏非常易于上手,且富有成效。

    有18位网友表示赞同!

初阳

通过抖音上的Android无障碍知识总结,我对辅助性技术有了更深刻的认识。

    有6位网友表示赞同!

呆檬

学习中遇到瓶颈时,这款游戏的寓教于乐方式很能吸引人,让我进步神速。

    有6位网友表示赞同!

無極卍盜

如果想要深入了解智能手机用户界面的无障碍设计,这个开发游戏是必选。

    有7位网友表示赞同!

今非昔比'

这款游戏帮助我从零开始了解Android中的无障碍元素和原理,很棒!

    有13位网友表示赞同!

(り。薆情海

我在找寻有关无障碍技术和实践的学习资源时,这个抖音上的Android系列真的帮了大忙!

    有20位网友表示赞同!

孤者何惧

作为初学者,我发现这款针对Android开发知识的游戏不仅丰富、生动,还非常有用。

    有17位网友表示赞同!

别悲哀

学习无障碍设计总是充满挑战,但通过游戏化的方式,我获得了很大的帮助和乐趣。

    有10位网友表示赞同!

满心狼藉

玩这款游戏的时候觉得自己的技能在不知不觉中提升,很适合时间碎片化的学习节奏。

    有6位网友表示赞同!

颓废i

对Android开发感兴趣的小伙伴可以玩这个游戏来认识一些基本的无障碍概念和实践。

    有18位网友表示赞同!

七夏i

从基础到进阶,这游戏覆盖了几乎所有我需要了解的Android无障碍开发相关知识点。

    有17位网友表示赞同!

如你所愿

虽然我是程序员背景的用户群之一,但这款游戏也帮助我拓宽了我的技能集。

    有16位网友表示赞同!

念旧是个瘾。

利用游戏的方式学习让整个过程既轻松又高效。对于新手来说,这是个很好的入门途径。

    有7位网友表示赞同!

执拗旧人

推荐给所有技术爱好者和初学者,尤其是那些想从不同角度了解更多关于用户体验设计的人。

    有13位网友表示赞同!

微信名字

作为Android开发者的一员,这是我遇到的最具吸引力的学习无障碍知识的游戏之一。

    有10位网友表示赞同!

孤街浪途

通过互动学习的方式,我真正理解和实践了Android中的无障碍功能,这真的很特别!

    有15位网友表示赞同!

軨倾词

这款游戏将专业知识与实用技能的提升完美结合,我很享受其中并从中获益良多。

    有14位网友表示赞同!

标题:抖音Android无障碍开发知识总结
链接:www.ggaan.com/news/rj/16883.html
版权:文章转载自网络,如有侵权,请联系删除!
资讯推荐
更多
小米mix fold有前置摄像头吗

小米mix fold有前置摄像头吗?作为小米的第一款折叠屏手机,这款手机可以说实话非常的强大,但是很多网友还是想要

2024-12-30
做超声检查时,医生为什么要在患者肚子上涂粘粘的东西

做B超为什么要涂凝胶?在支付宝蚂蚁庄园每日一题中,2021年4月9日的问题是问做超声检查时,医生为什么要在患者肚

2024-12-30
蚂蚁庄园4月10日答案最新

蚂蚁庄园4月10日答案最新是什么?在支付宝蚂蚁庄园每日一题中,你知道蚂蚁庄园2021年4月10日答案是什么吗?该怎么

2024-12-30
蚂蚁庄园4月13日答案最新

支付宝蚂蚁庄园今日答题答案是什么?在支付宝蚂蚁庄园每日一题中,每天都会刷新出现多个题目等待大家来回答,回答

2024-12-30