Android源码剖析:FocusFinder

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012591964/article/details/83058919

由于工作研究,需要优化一下焦点寻找逻辑,所以首先研究一下Android原生逻辑。

从源文件,我们可以看到,FocusFInder类大概1000行左右的代码量,并不多。

我们可以发现FucusFInlde使用了单例模式,不过由于使用了ThreadLocal,所以每一个线程都会拥有一个副本。

有2个方法可以寻找焦点,一种通过view,另外一种通过view的rec。

我们可以看到上述2个方法都调用了另外一个findNextFocus方法。effectiveRoot是指包含focused的ViewGroup,假如存在比root更加靠近的,并且getTouchscreenBlocksFocus(),isKeyboardNavigationCluster(),focused.getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)同时为true的Viewgroup,否则就是root。

100行调用了findNextUserSpecifiedFocus方法,195行方法将会根据预先给View设定的NextFocusId寻找usersetNextFocus.。198行开始的while循环中,有一个预防循环判断,由于findUserSetNextFocus是排除自身的,所以只需要间隔对比cycleCheck和userSetNextFocus即可排除循环。

108行调用addFocusables方法。1203行可以看到有一个FOCUS_BLOCK_DESCENDANTS的判断,由于直接return,所以将会拦截子View获取焦点,无论它自身是否可以处理。1214行有一个FOCUS_BEFORT_DESCENDANTS的判断,将会优先由自身处理,然后再分派给子View。1222行判断是否visible。

1226行调用FocusFinder中的sort方法。先利用rec.top,tec.bottom做一次排序,如下图方块1,2,3,4。844-861行,将会把方块根据rec.left,rec.right排序为1,2,4,3,前提是isRtl为false。1235行有一个FOCUS_AFTER_DESCENDANTS的判断,就是所有的子View都没有处理的话,将尝试自己处理。

110行调用findNextFocus方法,首先当focused不是null,可以直接获取focusedRect,并且转换坐标系到root。假如focused为null,直接根据direction取root的某一个点作为focusedRect。

268行调用findNextFocusInAbsoluteDirection方法,由于已经获取到focused相对于root的坐标。340-352行,首先把mBestCandidateRect根据direction初始化一个不可能的值。

367行调用isBetterCandidate方法,判断是否是一个更加好的预选值。主要是做交叉性,距离的对比优选,最后返回closeset。

最后,通过分析源码可以得知,每一次寻找焦点都需要调用focusables.cleat(),并且根据direction做繁杂的对比运算。在特定的场景,就是界面基本不会发生变化,我们可以唯一确定focusables队列,然后把每一个view计算得出的left,up,right,down方向的focusView保存起来,那么在下一次焦点寻找的时候就可以直接获取,不需要重复计算。

猜你喜欢

转载自blog.csdn.net/u012591964/article/details/83058919
今日推荐