Android View焦点总结

Android View焦点总结Android焦点相关逻辑大部分都在都在View, ViewGroup和FocusFinder三个类中。View对象都有一个mParent变量(添加到ViewGroup后), 代指其父容器. 绝大部分View的mParent都是ViewGroup类型, 除了根节点。一个Window中View根节点DecorView的mParent称为ViewRoot, 在安卓4.0后ViewRoot对应ViewRootImpl, 它不是View的子类, 而是个ViewParent。作者:佚名来源:Android开发中文站|2016-12-12 09:58?收藏??分享Android View焦点Android焦点相关逻辑大部分都在都在View, ViewGroup和FocusFinder三个类中.ViewRootView对象都有一个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(int d)设置onRequestFocusInDescendants方法是给子类重写使用, 可以控制子View处理焦点. 默认按照子View顺序处理, direction向下或向右则从第一个开始, 向上或向左则从最后一个开始, 直到某个子View获取焦点注意此方法只在此ViewGroup及其上层View上调用requestFocus时会执行到父容器焦点的处理在View获取焦点流程中会调用mParent.requestChildFocus, 维护View树上焦点唯一, 在各层ViewGroup中保存有焦点的子ViewViewGroup.java先清除自己的焦点, 如果原来内部有焦点, 先清除其焦点, 保存获取焦点的孩子, 然后调用上一层的requestChildFocus. 最后的调用可知, 这个方法会一直调用到View的树的root节点.在当前ViewGroup内部, 任何一个孩子取得焦点都会执行到这个方法, 因此此方法也是ViewGroup得知孩子焦点变化的方法之一.(可惜不能得知孩子失去焦点)失去焦点或清除焦点获取焦点可以是主动的, 但失去焦点一般都是被动的(见上面的代码), 因此逻辑相对简单, 只要清除焦点状态即可.ViewGroup.javaView.java注意上面的方法是默认package访问级别的, 我们无法重写也不能调用也可以主动清除焦点, 与获取焦点流