Android TV 焦点原理源码解析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android TV 焦点原理源码解析相关的知识,希望对你有一定的参考价值。
参考技术A相信很多刚接触androidTV开发的开发者,都会被各种焦点问题给折磨的不行。不管是学技术还是学习其他知识,都要学习和理解其中原理,碰到问题我们才能得心应手。下面就来探一探Android的焦点分发的过程。
Android焦点事件的分发是从ViewRootImpl的processKeyEvent开始的,源码如下:
源码比较长,下面我就慢慢来讲解一下具体的每一个细节。
dispatchKeyEvent方法返回true代表焦点事件被消费了。
ViewGroup的dispatchKeyEvent()方法的源码如下:
(2)ViewGroup的dispatchKeyEvent执行流程
(3)下面再来瞧瞧view的dispatchKeyEvent方法的具体的执行过程
惊奇的发现执行了onKeyListener中的onKey方法,如果onKey方法返回true,那么dispatchKeyEvent方法也会返回true
可以得出结论:如果想要修改ViewGroup焦点事件的分发,可以这么干:
注意:实际开发中,理论上所有焦点问题都可以通过给dispatchKeyEvent方法增加监听来来拦截来控制。
(1)dispatchKeyEvent方法返回false后,先得到按键的方向direction值,这个值是一个int类型参数。这个direction值是后面来进行焦点查找的。
(2)接着会调用DecorView的findFocus()方法一层一层往下查找已经获取焦点的子View。
ViewGroup的findFocus方法如下:
View的findFocus方法
说明:判断view是否获取焦点的isFocused()方法, (mPrivateFlags & PFLAG_FOCUSED) != 0 和view 的isFocused()方法是一致的。
其中isFocused()方法的作用是判断view是否已经获取焦点,如果viewGroup已经获取到了焦点,那么返回本身即可,否则通过mFocused的findFocus()方法来找焦点。mFocused其实就是ViewGroup中获取焦点的子view,如果mView不是ViewGourp的话,findFocus其实就是判断本身是否已经获取焦点,如果已经获取焦点了,返回本身。
(3)回到processKeyEvent方法中,如果findFocus方法返回的mFocused不为空,说明找到了当前获取焦点的view(mFocused),接着focusSearch会把direction(遥控器按键按下的方向)作为参数,找到特定方向下一个将要获取焦点的view,最后如果该view不为空,那么就让该view获取焦点。
(4)focusSearch方法的具体实现。
focusSearch方法的源码如下:
可以看出focusSearch其实是一层一层地网上调用父View的focusSearch方法,直到当前view是根布局(isRootNamespace()方法),通过注释可以知道focusSearch最终会调用DecorView的focusSearch方法。而DecorView的focusSearch方法找到的焦点view是通过FocusFinder来找到的。
(5)FocusFinder是什么?
它其实是一个实现 根据给定的按键方向,通过当前的获取焦点的View,查找下一个获取焦点的view这样算法的类。焦点没有被拦截的情况下,Android框架焦点的查找最终都是通过FocusFinder类来实现的。
(6)FocusFinder是如何通过findNextFocus方法寻找焦点的。
下面就来看看FocusFinder类是如何通过findNextFocus来找焦点的。一层一层往下看,后面会执行findNextUserSpecifiedFocus()方法,这个方法会执行focused(即当前获取焦点的View)的findUserSetNextFocus方法,如果该方法返回的View不为空,且isFocusable = true && isInTouchMode() = true的话,FocusFinder找到的焦点就是findNextUserSpecifiedFocus()返回的View。
(7)findNextFocus会优先根据XML里设置的下一个将获取焦点的View ID值来寻找将要获取焦点的View。
看看View的findUserSetNextFocus方法内部都干了些什么,OMG不就是通过我们xml布局里设置的nextFocusLeft,nextFocusRight的viewId来找焦点吗,如果按下Left键,那么便会通过nextFocusLeft值里的View Id值去找下一个获取焦点的View。
可以得出以下结论:
1. 如果一个View在XML布局中设置了focusable = true && isInTouchMode = true,那么这个View会优先获取焦点。
2. 通过设置nextFocusLeft,nextFocusRight,nextFocusUp,nextFocusDown值可以控制View的下一个焦点。
Android焦点的原理实现就这些。总结一下:
为了方便同志们学习,我这做了张导图,方便大家理解~
Android TV 焦点与按键事件分析
转自:http://blog.csdn.net/yummykwok/article/details/56667260
在触摸屏出现在手机上之前,焦点是手机上人机交互中最重要的一个概念。焦点即用户当前的关注点(或区域),手机上将该区域以某种形式高亮显示,人们通过上、下、左、右方向键可以移动焦点,按确认键后手机将打开(或呈显)与当前焦点关联的内容;触摸屏的出现大大地简化了人机交互,触摸事件(TouchEvent)成了核心,焦点的存在感就很小了。
但是对于电视来说,其显示屏面积大,人机距离远,触摸屏的方案显然不合理。因此目前Android电视的人机交互仍旧使用遥控器为主,焦点的重要性在电视上又显现出来了。通过遥控器将方向键或确认键信号(或信息)发送到电视端后,转换为标准按键事件(KeyEvent),而按键事件分发最终目标就是焦点。
1、初识View之焦点
View是UI组件的基本构建,也自然就是焦点的承载者。View是否可聚焦,由FOCUSABLE和FOCUSABLE_IN_TOUCH_MODE(触摸模式下也可以有焦点)两个FLAG标识。
[java] view plain copy
- public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)
- this(context);
- final TypedArray a = context.obtainStyledAttributes(
- attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);
- final int N = a.getIndexCount();
- for (int i = 0; i < N; i++)
- int attr = a.getIndex(i);
- switch (attr)
- ……
- case com.android.internal.R.styleable.View_focusable:
- if (a.getBoolean(attr, false))
- viewFlagValues |= FOCUSABLE;
- viewFlagMasks |= FOCUSABLE_MASK;
- break;
- case com.android.internal.R.styleable.View_focusableInTouchMode:
- if (a.getBoolean(attr, false))
- viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE;
- viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK;
- break;
- ……
- ……
[java] view plain copy
- public class Button extends TextView
- ……
- public Button(Context context, AttributeSet attrs)
- this(context, attrs, com.android.internal.R.attr.buttonStyle);
- ……
Button设置了一个默认的style,我们找出源码看看,
[html] view plain copy- <stylenamestylename="Widget.Button">
- <itemnameitemname="background">@drawable/btn_default</item>
- <strong><itemnameitemname="focusable">true</item></strong>
- <itemnameitemname="clickable">true</item>
- <itemnameitemname="textAppearance">?attr/textAppearanceSmallInverse</item>
- <itemnameitemname="textColor">@color/primary_text_light</item>
- 以上是关于Android TV 焦点原理源码解析的主要内容,如果未能解决你的问题,请参考以下文章
Android源码解析RPC系列(一)---Binder原理