美文网首页android开发
Android View焦点总结

Android View焦点总结

作者: passiontim | 来源:发表于2017-09-23 14:34 被阅读195次

本来之前说view下篇是写onMeasure,onLayou,onDraw相关的,笔者做盒子开发,遥控器按键,碰到的都是焦点控制相关。所以先把焦点放到了onMeasure,onLayou,onDraw之前。

    • ViewRoot

    • View的焦点

    • ViewGroup的焦点

    • 父容器焦点的处理

    • 失去焦点或清除焦点

    • 焦点移动

    • FocusFinder查找焦点

    • 总结

Android View焦点

Android焦点相关逻辑大部分都在都在View, ViewGroup和FocusFinder三个类中.

ViewRoot

View对象都有一个mParent变量(添加到ViewGroup后), 代指其父容器. 绝大部分View的mParent都是ViewGroup类型, 除了根节点. 一个Window中View根节点DecorView的mParent称为ViewRoot, 在安卓4.0后ViewRoot对应ViewRootImpl, 它不是View的子类, 而是个ViewParent. ViewRootImpl是连接Window和DecorView的纽带, View的焦点, 按键, 布局, 渲染等流程都是从ViewRoot中开始的.

View的焦点

基本流程如下

View(包括ViewGroup)获取焦点都通过如下三个方法

View.java


从上面可以看到前两个最终会执行到第三个方法.

最后的requestFocusNoSearch先判断是否可以获取焦点, 然后进入下面的最后流程:

View.java


上面的流程比较简单: 如果当前没有焦点, 先置焦点标志, 再通知parent, 然后刷新图片.

  1. 主要的流程在mParent的requestChildFocus里面, 后面会分析. 那里会逐层向上修改焦点View并清除原来有焦点的View的焦点

  2. onFocusChange会触发invalidate刷新, 然后调用onFocusChangeListener. 默认情况每个View只能设置一个onFocusChangeListener, 而开发中经常遇到需要设置多个Listener的情况, 我们就可以重写onFocusChange方法, 实现回调多个onFocusChangeListener的需求.

ViewGroup的焦点

ViewGroup获取焦点是在View获取焦点流程中多了内部焦点处理

ViewGroup.java


上面代码中descendantFocusability决定了是先按View焦点流程处理(自己处理焦点)还是先把给子View处理

  • FOCUS_BLOCK_DESCENDANTS 不允许子View获取焦点, 那么按照View的流程进行

  • FOCUS_BEFORE_DESCENDANTS 先按照View的流程处理, 如果自己不能获取焦点则给孩子处理

  • FOCUS_AFTER_DESCENDANTS 先尝试给孩子焦点, 如果没有可获取焦点再按照View流程自己获取焦点

默认值FOCUS_BEFORE_DESCENDANTS, 我们可以通过setDescendantFocusability(int d)设置

onRequestFocusInDescendants方法是给子类重写使用, 可以控制子View处理焦点. 默认按照子View顺序处理, direction向下或向右则从第一个开始, 向上或向左则从最后一个开始, 直到某个子View获取焦点

注意此方法只在此ViewGroup及其上层View上调用requestFocus时会执行到

父容器焦点的处理

在View获取焦点流程中会调用mParent.requestChildFocus, 维护View树上焦点唯一, 在各层ViewGroup中保存有焦点的子View

ViewGroup.java


先清除自己的焦点, 如果原来内部有焦点, 先清除其焦点, 保存获取焦点的孩子, 然后调用上一层的requestChildFocus. 最后的调用可知, 这个方法会一直调用到View的树的root节点.

在当前ViewGroup内部, 任何一个孩子取得焦点都会执行到这个方法, 因此此方法也是ViewGroup得知孩子焦点变化的方法之一.(可惜不能得知孩子失去焦点)

失去焦点或清除焦点

获取焦点可以是主动的, 但失去焦点一般都是被动的(见上面的代码), 因此逻辑相对简单, 只要清除焦点状态即可.

ViewGroup.java


View.java


注意上面的方法是默认package访问级别的, 我们无法重写也不能调用

也可以主动清除焦点, 与获取焦点流程相似

ViewGroup.java


View.java


ViewGroup.java


以上是安卓View系统焦点处理的全部流程和涉及到的方法, ViewRootImpl的requestChildFocus和clearChildFocus实现我们不需要关注

另外还有以下一些辅助方法

  • boolean isFocusable() View是否可以获取焦点

  • boolean isFocused() View是否获取焦点

  • boolean hasFocus() View/ViewGroup内部是否有焦点

  • View findFocus() 取到View/ViewGroup内部的焦点View

  • View getFocusedChild() 取到ViewGroup内部有焦点的子View

  • View getRootView() 取到根节点View(一般是DecorView或顶层ViewGroup)

焦点移动

除了在代码里面控制焦点, 系统对没有处理的方向键等一些按键自动按照焦点移动来处理, 见下面代码

ViewRootImpl.java



代码比较上, 但是主要做了三个步骤

  1. 如果View没有处理按键, 把上下左右tab等按键转换成对应方向

  2. 在当前焦点View上通过focusSearch方法查找对应方向的下一个View

  3. 查找到的View调用requestFocus
    因此主要的流程在focusSearch中

View.java


普通View查找什么都没做, 交给parent来完成.

ViewGroup.java


ViewRootImpl


我们可以重写focusSearch控制焦点移动顺序, 而默认的焦点移动顺序由FocusFinder决定

FocusFinder查找焦点

FocusFinder为public的工具类, 主要就两个方法, 可以在给定的View内在指定方向查找指定View或坐标的下一个焦点
如下:

核心逻辑就两步, 先查找setNextFocusXXId设置的View, 如果没有按照就近算法查找.
具体算法不再分析, SDK里面有源码.

总结

综合上面的流程分析, 我们在实现自定义View时, 对焦点的特殊需求有如下思路

  1. requestFocus和clearFocus直接对View清除或转移焦点

  2. 除了onFocusChangeListener, 还可以在onFocusChange方法中实现一些View失去/获得焦点时通知

  3. 对ViewGroup, 如果只需要在子View获取焦点时得到通知, 有requestChildFocus方法.

  4. 重写onRequestFocusInDescendants方法可以控制某些情景下ViewGroup焦点

  5. 控制焦点移动可以重写focusSearch方法

  6. 另外还有FocusFinder工具和上面的辅助方法.

相关文章

  • Android View焦点总结

    本来之前说view下篇是写onMeasure,onLayou,onDraw相关的,笔者做盒子开发,遥控器按键,碰到...

  • Android View总结

    作者:threezj原文地址:Android View总结 关于Android View控件 Android中控件...

  • Android焦点问题

    Android焦点分发主要涉及的方法就是findFocus:View都有,发现焦点requestFocus:Vie...

  • : 标签用于指定屏幕内的焦点View。android requestFocus的使用

  • 知识点总结

    知识点总结 Android View View的滑动方式layout(left,top,right,bottom)...

  • android view 选中效果高光消除

    扫码qiang禁用键盘,然后焦点就有问题。可以定义一个view抢占焦点,避免焦点乱跑。使用android:defa...

  • android View事件体系结论总结

    在了解android view事件体系前,先了解下android UI界面架构图。 从上图可以简单总结出view触...

  • Android View 动画框架总结

    Android View 动画框架总结 1. 视图动画 ( Animation ):Android 3.0之前就存...

  • Android View获取焦点

    做项目的时候遇到一个bug,在一个Activity中打开DrawerLayout,这样就会遇到一个问题,在Acti...

  • 高级Android工程师进阶系列文章汇总

    自定义View HenCoder(朱凯)自定义View系列 自定义view总结 Android 样式的开发 And...

网友评论

    本文标题:Android View焦点总结

    本文链接:https://www.haomeiwen.com/subject/qtecextx.html