Android View焦点总结.docx
- 文档编号:24278847
- 上传时间:2023-05-26
- 格式:DOCX
- 页数:13
- 大小:1.55MB
Android View焦点总结.docx
《Android View焦点总结.docx》由会员分享,可在线阅读,更多相关《Android View焦点总结.docx(13页珍藏版)》请在冰豆网上搜索。
AndroidView焦点总结
AndroidView焦点总结
Android焦点相关逻辑大部分都在都在View,ViewGroup和FocusFinder三个类中。
View对象都有一个mParent变量(添加到ViewGroup后),代指其父容器.绝大部分View的mParent都是ViewGroup类型,除了根节点。
一个Window中View根节点DecorView的mParent称为ViewRoot,在安卓4.0后ViewRoot对应ViewRootImpl,它不是View的子类,而是个ViewParent。
作者:
佚名来源:
Android开发中文站|2016-12-1209:
58
收藏
分享
AndroidView焦点
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,然后刷新图片.
主要的流程在mParent的requestChildFocus里面,后面会分析.那里会逐层向上修改焦点View并清除原来有焦点的View的焦点
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(intd)
设置
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实现我们不需要关注
另外还有以下一些辅助方法
booleanisFocusable()View是否可以获取焦点
booleanisFocused()View是否获取焦点
booleanhasFocus()View/ViewGroup内部是否有焦点
ViewfindFocus()取到View/ViewGroup内部的焦点View
ViewgetFocusedChild()取到ViewGroup内部有焦点的子View
ViewgetRootView()取到根节点View(一般是DecorView或顶层ViewGroup)
焦点移动
除了在代码里面控制焦点,系统对没有处理的方向键等一些按键自动按照焦点移动来处理,见下面代码
ViewRootImpl.java
代码比较上,但是主要做了三个步骤
如果View没有处理按键,把上下左右tab等按键转换成对应方向
在当前焦点View上通过focusSearch方法查找对应方向的下一个View
查找到的View调用requestFocus因此主要的流程在focusSearch中
View.java
普通View查找什么都没做,交给parent来完成.
ViewGroup.java
ViewRootImpl
我们可以重写focusSearch控制焦点移动顺序,而默认的焦点移动顺序由FocusFinder决定
FocusFinder查找焦点
FocusFinder为public的工具类,主要就两个方法,可以在给定的View内在指定方向查找指定View或坐标的下一个焦点如下:
核心逻辑就两步,先查找setNextFocusXXId设置的View,如果没有按照就近算法查找.具体算法不再分析,SDK里面有源码.
总结
综合上面的流程分析,我们在实现自定义View时,对焦点的特殊需求有如下思路
requestFocus和clearFocus直接对View清除或转移焦点
除了onFocusChangeListener,还可以在onFocusChange方法中实现一些View失去/获得焦点时通知
对ViewGroup,如果只需要在子View获取焦点时得到通知,有requestChildFocus方法.
重写onRequestFocusInDescendants方法可以控制某些情景下ViewGroup焦点
控制焦点移动可以重写focusSearch方法
另外还有FocusFinder工具和上面的辅助方法.
【编辑推荐】
1.图解Android事件分发机制
2.Android混淆从入门到精通
3.Android触摸事件(笔记篇)
4.android四大组件之Service
5.Android开发中,那些让你相见恨晚的方法、类或接口
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android View焦点总结 View 焦点 总结