内容简介:在tv端开发中,焦点处理是一个非常重要的技术。该篇主要是想整理相关知识。(本文档依据sdk26进行分析)在android的绘制流程中**ViewRootImpl#performTraversals()**起着关键的作用,而焦点状态也会通过影响视图的绘制。下面来看看android事如何进行第一次寻焦的
在tv端开发中,焦点处理是一个非常重要的技术。该篇主要是想整理相关知识。(本文档依据sdk26进行分析)
第一次寻焦
在android的绘制流程中**ViewRootImpl#performTraversals()**起着关键的作用,而焦点状态也会通过影响视图的绘制。
下面来看看android事如何进行第一次寻焦的
private void performTraversals() { ...... if (mFirst && sAlwaysAssignFocus) { // handle first focus request if (mView != null) { if (!mView.hasFocus()) { mView.restoreDefaultFocus(); } } } ...... } 复制代码
mView.restoreDefaultFocus() 将会去查找当前试图第一个可聚焦的View。将会执行 requestFocus(int direction, Rect previouslyFocusedRect) 。因为ViewGroup重写了该方法,增加了是否拦截焦点处理的逻辑,下面我们先来看看 ViewGroup#requestFocus(int direction, Rect previouslyFocusedRect)
@Override public boolean requestFocus(int direction, Rect previouslyFocusedRect) { if (DBG) { System.out.println(this + " ViewGroup.requestFocus direction=" + direction); } int descendantFocusability = getDescendantFocusability(); switch (descendantFocusability) { //拦截焦点,不管当前View是否被聚焦,子View一定获取不到焦点。 case FOCUS_BLOCK_DESCENDANTS: return super.requestFocus(direction, previouslyFocusedRect); //在子View之前判断是否应被聚焦,如果为false则会去判断其子View case FOCUS_BEFORE_DESCENDANTS: { final boolean took = super.requestFocus(direction, previouslyFocusedRect); return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect); } // 在子View判断焦点之后判断 case FOCUS_AFTER_DESCENDANTS: { final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect); return took ? took : super.requestFocus(direction, previouslyFocusedRect); } default: throw new IllegalStateException("descendant focusability must be " + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS " + "but is " + descendantFocusability); } } 复制代码
接着我们来看看 View#requestFocus(int direction, Rect previouslyFocusedRect)
public boolean requestFocus(int direction, Rect previouslyFocusedRect) { return requestFocusNoSearch(direction, previouslyFocusedRect); } private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { // 判断是否可被聚焦 if ((mViewFlags & FOCUSABLE) != FOCUSABLE || (mViewFlags & VISIBILITY_MASK) != VISIBLE) { return false; } // 判断触摸状态下是否可被聚焦 if (isInTouchMode() && (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { return false; } // 判断父View是否需要拦截 if (hasAncestorThatBlocksDescendantFocus()) { return false; } //执行聚焦操作 handleFocusGainInternal(direction, previouslyFocusedRect); return true; } void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { if (DBG) { System.out.println(this + " requestFocus()"); } if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { //设置聚焦标志位 mPrivateFlags |= PFLAG_FOCUSED; View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; if (mParent != null) { //通知父容器改变焦点View mParent.requestChildFocus(this, this); updateFocusedInCluster(oldFocus, direction); } if (mAttachInfo != null) { //全局监听回调 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); } //执行焦点变化与强制绘制 onFocusChanged(true, direction, previouslyFocusedRect); refreshDrawableState(); } } 复制代码
遥控器方向键后的寻焦逻辑
首先会根据按键生成一个寻焦方向(可以查看ViewRootImpl#ViewPostImeInputStage#processKeyEvent)
private int processKeyEvent(QueuedInputEvent q) { ...... //上面是判断是否处理当前按键,如dispatchKeyEvent返回true则不会执行下面的焦点逻辑 // 根据当前事件生成一个寻焦方向。 if (event.getAction() == KeyEvent.ACTION_DOWN) { int direction = 0; switch (event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_LEFT: if (event.hasNoModifiers()) { direction = View.FOCUS_LEFT; } break; case KeyEvent.KEYCODE_DPAD_RIGHT: if (event.hasNoModifiers()) { direction = View.FOCUS_RIGHT; } break; case KeyEvent.KEYCODE_DPAD_UP: if (event.hasNoModifiers()) { direction = View.FOCUS_UP; } break; case KeyEvent.KEYCODE_DPAD_DOWN: if (event.hasNoModifiers()) { direction = View.FOCUS_DOWN; } break; case KeyEvent.KEYCODE_TAB: if (event.hasNoModifiers()) { direction = View.FOCUS_FORWARD; } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { direction = View.FOCUS_BACKWARD; } break; } if (direction != 0) { //查询当前聚集view,根据当前view查询下一个方向的聚焦view View focused = mView.findFocus(); if (focused != null) { //由此可见,focusSearch 为寻焦的主要方法,可重新该方法来修改焦点逻辑 View v = focused.focusSearch(direction); if (v != null && v != focused) { // do the math the get the interesting rect // of previous focused into the coord system of // newly focused view focused.getFocusedRect(mTempRect); if (mView instanceof ViewGroup) { ((ViewGroup) mView).offsetDescendantRectToMyCoords( focused, mTempRect); ((ViewGroup) mView).offsetRectIntoDescendantCoords( v, mTempRect); } if (v.requestFocus(direction, mTempRect)) { playSoundEffect(SoundEffectConstants .getContantForFocusDirection(direction)); return FINISH_HANDLED; } } // Give the focused view a last chance to handle the dpad key. if (mView.dispatchUnhandledMove(focused, direction)) { return FINISH_HANDLED; } } else { // find the best view to give focus to in this non-touch-mode with no-focus View v = focusSearch(null, direction); if (v != null && v.requestFocus(direction)) { return FINISH_HANDLED; } } } } return FORWARD; } 复制代码
下面可查看View#focusSearch与ViewGroup#focusSearch 的相关处理
View.java public View focusSearch(@FocusRealDirection int direction) { if (mParent != null) { return mParent.focusSearch(this, direction); } else { return null; } } ViewGroup.java public View focusSearch(View focused, int direction) { if (isRootNamespace()) { // 通过FocusFinder来查找下一个聚焦view return FocusFinder.getInstance().findNextFocus(this, focused, direction); } else if (mParent != null) { return mParent.focusSearch(focused, direction); } return null; } 复制代码
FocusFinder 是一个焦点处理的类,主要用于在一个方向上,通过当前view与聚焦方案来合理判断下一个被聚焦view
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 大数据分析市场潜力巨大 业务价值以已成关注焦点
- Python 爬取爱奇艺 52432 条数据分析谁才是《奇葩说》的焦点人物?
- HTML5-焦点管理
- 简单的输入框焦点动画效果
- DOM 元素中的焦点管理
- android音视频指南-管理音频焦点
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java5.0Tiger程序高手秘笈
BrettMclaughlin / 东南大学出版社 / 2005-10 / 28.00元
代号为 “Tiger”的下一个 Java 版本,不只是个小改动版。在语言核心中有超过 100 项以上的变动,同时有大量的对 library 与 API 所做的加强,让开发者取得许多新的功能、工具与技术。但在如此多的变化下,应该从何处开始着手?也许可以从既长又无趣的语言规范说明书开始看起;或等待最少 500 页的概念与理论巨著出版;甚至还可以直接把玩新的 JDK 看看能够有什么发现;或者借由《Jav......一起来看看 《Java5.0Tiger程序高手秘笈》 这本书的介绍吧!