本文主要是介绍关于View的焦点,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
##1.什么是View/ViewGroup的焦点,焦点的作用是什么?
从广义上来说,焦点就是用户当前正在或者下一步可能操作的目标,在按键模式下(现在大部分手机都是触摸模式)一般具有焦点的View都会高亮展示,以提示用户当前可以操作的目标。
从狭义上来说,焦点就是View中的mPrivateFlags成员字段被添加上了PFLAG_FOCUSED标示。
##2.View和ViewGroup中hasFocus方法的区别?
//View的hasFocus方法public boolean hasFocus() {return (mPrivateFlags & PFLAG_FOCUSED) != 0;}//ViewGroup的hasFocus方法public boolean hasFocus() {return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;}
上述是View的hasFocus方法就是去检查当前view的mPrivateFlags字段中是否具有PFLAG_FOCUSED,而ViewGroup的hasFocus方法出了检查PFLAG_FOCUSED,还可以检查mFocused变量,也就是说ViewGroup的hasFocus方法返回两种情况
- 当前ViewGroup自身就是焦点所有者
- 当前ViewGroup自身没有焦点,但是具有焦点的控件在其子View中,这个时候mFocused就是焦点链路上的一个节点
上述的绿色背景的节点就构成了一个焦点链路,最顶层的ViewGroup的mFocused执行第二层的ViewGroup,第二层的中的mFocused指向View,该View就是真正获取到焦点的控件
##3.View.requestFocus方法是怎么获取和释放焦点的?
public final boolean requestFocus() {return requestFocus(View.FOCUS_DOWN);}public boolean requestFocus(int direction, Rect previouslyFocusedRect) {return requestFocusNoSearch(direction, previouslyFocusedRect);}private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {// need to be focusable// 检查当前View是否能具有焦点if ((mViewFlags & FOCUSABLE) != FOCUSABLE|| (mViewFlags & VISIBILITY_MASK) != VISIBLE) {return false;}// need to be focusable in touch mode if in touch mode// 如果是触摸模式,则还会检查其在该模式下是否具有焦点资格if (isInTouchMode() &&(FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) {return false;}// need to not have any parents blocking us// 检查其所属的ViewGroup是否管控了焦点分发策略,后面会说道if (hasAncestorThatBlocksDescendantFocus()) {return false;}//开始焦点更换流程handleFocusGainInternal(direction, previouslyFocusedRect);return true;}
view的requestFocus方法先检查当前View是否具有获取焦点的资格,之后再检查是否在触摸模式下,如果在该模式下,则还会检查是否具有触摸模式的焦点资格(在控件系统中,存在两种模式,分别是按键模式和触摸模式)。之后会检查其ViewGroup是否允许子View获取焦点,当ViewGroup中具有FOCUS_BLOCK_DESCENDANTS标示时,就会阻止子View获取焦点,如果允许子View获取焦点,则开始焦点请求
//如果当前View不是焦点控件,才进行后续操作if ((mPrivateFlags & PFLAG_FOCUSED) == 0) {//给当前View加上焦点标示mPrivateFlags |= PFLAG_FOCUSED;//先找到最顶层的ViewGroup,之后根据焦点链路找到前一个真正的焦点控件View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null;if (mParent != null) {// 通过mParent向上一级View回溯,通知ViewGroup焦点控件更换了,让ViewGroup更新焦点链路mParent.requestChildFocus(this, this);updateFocusedInCluster(oldFocus, direction);}if (mAttachInfo != null) {mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this);}//通知焦点观察者,焦点改变了onFocusChanged(true, direction, previouslyFocusedRect);// 刷新视图展示,比如在按键模式下,具有焦点的控件会高亮显示refreshDrawableState();}
接下来看下ViewGroup的requestChildFocus方法:
@Overridepublic void requestChildFocus(View child, View focused) {// 再次检查当前ViewGroup焦点拦截策略if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {return;}// Unfocus us, if necessarysuper.unFocus(focused);// 如果当前ViewGroup是之前的焦点链路上的一个节点,则mFocused节点去释放焦点(清空焦点标示)if (mFocused != child) {if (mFocused != null) {mFocused.unFocus(focused);}mFocused = child;}if (mParent != null) {//不断向上一集View回溯,直到更新了整个View树的焦点链路,注意这里的第一个参数不是之前的焦点控件了,而是当前ViewGroup了mParent.requestChildFocus(this, focused);}}
看下View的unFocus方法:
void unFocus(View focused) {clearFocusInternal(focused, false, false);}void clearFocusInternal(View focused, boolean propagate, boolean refocus) {if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {//清空焦点标示mPrivateFlags &= ~PFLAG_FOCUSED;if (propagate && mParent != null) {//向上级View回溯,清空焦点mParent.clearChildFocus(this);}onFocusChanged(false, 0, null);refreshDrawableState();if (propagate && (!refocus || !rootViewRequestFocus())) {notifyGlobalFocusCleared(this);}}}
这篇关于关于View的焦点的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!