voidsetFlags(int flags, int mask){ int old = mViewFlags; mViewFlags = (mViewFlags & ~mask) | (flags & mask);
int changed = mViewFlags ^ old; if (changed == 0) { return; } int privateFlags = mPrivateFlags; boolean shouldNotifyFocusableAvailable = false;
// If focusable is auto, update the FOCUSABLE bit. int focusableChangedByAuto = 0; if (((mViewFlags & FOCUSABLE_AUTO) != 0) && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { // Heuristic only takes into account whether view is clickable. finalint newFocus; if ((mViewFlags & CLICKABLE) != 0) { newFocus = FOCUSABLE; } else { newFocus = NOT_FOCUSABLE; } mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; }
/* Check if the FOCUSABLE bit has changed */ if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { if (((old & FOCUSABLE) == FOCUSABLE) && ((privateFlags & PFLAG_FOCUSED) != 0)) { /* Give up focus if we are no longer focusable */ clearFocus(); if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).clearFocusedInCluster(); } } elseif (((old & FOCUSABLE) == NOT_FOCUSABLE) && ((privateFlags & PFLAG_FOCUSED) == 0)) { /* * Tell the view system that we are now available to take focus * if no one else already has it. */ if (mParent != null) { ViewRootImpl viewRootImpl = getViewRootImpl(); if (!sAutoFocusableOffUIThreadWontNotifyParents || focusableChangedByAuto == 0 || viewRootImpl == null || viewRootImpl.mThread == Thread.currentThread()) { shouldNotifyFocusableAvailable = canTakeFocus(); } } } } }
if (mFirst) { // 当系统版本小于28时,sAlwaysAssignFocus为true if (sAlwaysAssignFocus || !isInTouchMode()) { // handle first focus request // mView 为 DecorView if (mView != null) { if (!mView.hasFocus()) { // 将焦点产生在DecorView上 mView.restoreDefaultFocus(); } } } else { // Some views (like ScrollView) won't hand focus to descendants that aren't within // their viewport. Before layout, there's a good change these views are size 0 // which means no children can get focus. After layout, this view now has size, but // is not guaranteed to hand-off focus to a focusable child (specifically, the edge- // case where the child has a size prior to layout and thus won't trigger // focusableViewAvailable). // 确保ScrollView等滑动View的子View会正确的获取到焦点 View focused = mView.findFocus(); if (focused instanceof ViewGroup && ((ViewGroup) focused).getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS) { focused.restoreDefaultFocus(); } } }
privateintprocessKeyEvent(QueuedInputEvent q){ final KeyEvent event = (KeyEvent)q.mEvent;
if (mUnhandledKeyManager.preViewDispatch(event)) { return FINISH_HANDLED; }
// Deliver the key to the view hierarchy. // 在视图树上依次分发,判断焦点View是否自行处理KeyEvent, // 如果自定义key事件并返回true,后续不再执行 if (mView.dispatchKeyEvent(event)) { return FINISH_HANDLED; }
//一些保护措施 //在View层次结构不消费事件,判断窗口是否有输入事件或者已经停止和销毁 if (shouldDropInputEvent(q)) { return FINISH_NOT_HANDLED; }
// This dispatch is for windows that don't have a Window.Callback. Otherwise, // the Window.Callback usually will have already called this (see // DecorView.superDispatchKeyEvent) leaving this call a no-op. if (mUnhandledKeyManager.dispatch(mView, event)) { return FINISH_HANDLED; }
// If a modifier is held, try to interpret the key as a shortcut. if (event.getAction() == KeyEvent.ACTION_DOWN && !KeyEvent.metaStateHasNoModifiers(event.getMetaState()) && event.getRepeatCount() == 0 && !KeyEvent.isModifierKey(event.getKeyCode()) && groupNavigationDirection == 0) { // 对快捷键进行处理,目前子View只有TextView进行了实现。 if (mView.dispatchKeyShortcutEvent(event)) { return FINISH_HANDLED; } if (shouldDropInputEvent(q)) { return FINISH_NOT_HANDLED; } }
// Apply the fallback event policy. if (mFallbackEventHandler.dispatchKeyEvent(event)) { return FINISH_HANDLED; } if (shouldDropInputEvent(q)) { return FINISH_NOT_HANDLED; }
// Handle automatic focus changes. if (event.getAction() == KeyEvent.ACTION_DOWN) { if (groupNavigationDirection != 0) { // 执行组合键策略 if (performKeyboardGroupNavigation(groupNavigationDirection)) { return FINISH_HANDLED; } } else { // 执行上下左右键策略 if (performFocusNavigation(event)) { return FINISH_HANDLED; } } } return FORWARD; }
privatebooleanrequestFocusNoSearch(int direction, Rect previouslyFocusedRect){ // need to be focusable // 检测view可见性、layout空间大小等 if (!canTakeFocus()) { returnfalse; }
// need to be focusable in touch mode if in touch mode // 判断当前是否为触摸模式与是否配置了focusableInTouchMode = true if (isInTouchMode() && (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { returnfalse; }
// need to not have any parents blocking us // 判断是否有父View拦截焦点事件 if (hasAncestorThatBlocksDescendantFocus()) { returnfalse; }
publicbooleanrequestFocus(int direction, Rect previouslyFocusedRect){ // 获取配置的descendantFocusability int descendantFocusability = getDescendantFocusability();
boolean result; switch (descendantFocusability) { case FOCUS_BLOCK_DESCENDANTS: // 直接请求自己的requestFocus result = super.requestFocus(direction, previouslyFocusedRect); break; case FOCUS_BEFORE_DESCENDANTS: { // 1. 先自行进行请求焦点 finalboolean took = super.requestFocus(direction, previouslyFocusedRect); // 2. 如果自己不获取焦点,那么就通过onRequestFocusInDescendants方法分发到子View上 result = took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect); break; } case FOCUS_AFTER_DESCENDANTS: { // 1. 先通过onRequestFocusInDescendants尝试分发给子View finalboolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect); // 2. 如果子view不获取焦点,那么自己请求焦点 result = took ? took : super.requestFocus(direction, previouslyFocusedRect); break; } default: thrownew IllegalStateException("descendant focusability must be " + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS " + "but is " + descendantFocusability); } if (result && !isLayoutValid() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) { mPrivateFlags |= PFLAG_WANTS_FOCUS; } return result; }
// Unfocus us, if necessary // 主要作用为如果当前ViewGroup为焦点View,那么清除当前 ViewGroup 的焦点 super.unFocus(focused);
// We had a previous notion of who had focus. Clear it. if (mFocused != child) { if (mFocused != null) { // 清除当前存储的View的焦点状态 mFocused.unFocus(focused); } // 更改存储的聚焦的view mFocused = child; } if (mParent != null) { // 这里一层一层向上通知焦点View的改变 mParent.requestChildFocus(this, focused); } }
// Since requestFocus only takes "real" focus directions (and therefore also // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN. int realDirection = direction; if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) { realDirection = View.FOCUS_DOWN; } // 3. 通过调用restoreFocusNotInCluster restoreFocusInCluster切换焦点 if (cluster != null && cluster.isRootNamespace()) { // the default cluster. Try to find a non-clustered view to focus. if (cluster.restoreFocusNotInCluster()) { playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); returntrue; } // otherwise skip to next actual cluster cluster = keyboardNavigationClusterSearch(null, direction); }
public View keyboardNavigationClusterSearch(View currentCluster, @FocusDirectionint direction){ if (isKeyboardNavigationCluster()) { currentCluster = this; } if (isRootNamespace()) { // Root namespace means we should consider ourselves the top of the // tree for group searching; otherwise we could be group searching // into other tabs. see LocalActivityManager and TabHost for more info. // 如果是根View,则代理给FocusFinder负责进行搜寻工作 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( this, currentCluster, direction); } elseif (mParent != null) { // 一层一层向上找根View return mParent.keyboardNavigationClusterSearch(currentCluster, direction); } returnnull; }
privatebooleanperformFocusNavigation(KeyEvent event){ int direction = 0; // 1. 根据按键确定方向 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; } elseif (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { direction = View.FOCUS_BACKWARD; } break; } if (direction != 0) { // 2. 找到当前聚焦的View View focused = mView.findFocus(); if (focused != null) { // 3. 寻找需要获取焦点的View 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); } // 4. 进行焦点状态的切换 if (v.requestFocus(direction, mTempRect)) { playSoundEffect(SoundEffectConstants .getContantForFocusDirection(direction)); returntrue; } }
// Give the focused view a last chance to handle the dpad key. if (mView.dispatchUnhandledMove(focused, direction)) { returntrue; } } else { // 当没有焦点时产生默认的焦点 if (mView.restoreDefaultFocus()) { returntrue; } } } returnfalse; }
public View focusSearch(@FocusRealDirectionint direction){ if (mParent != null) { return mParent.focusSearch(this, direction); } else { returnnull; } }
ViewGroup.java
1 2 3 4 5 6 7 8 9 10 11
public View focusSearch(View focused, int direction){ if (isRootNamespace()) { // root namespace means we should consider ourselves the top of the // tree for focus searching; otherwise we could be focus searching // into other tabs. see LocalActivityManager and TabHost for more info. return FocusFinder.getInstance().findNextFocus(this, focused, direction); } elseif (mParent != null) { return mParent.focusSearch(focused, direction); } returnnull; }
voidsetFlags(int flags, int mask){ finalint newVisibility = flags & VISIBILITY_MASK; if (newVisibility == VISIBLE) { if ((changed & VISIBILITY_MASK) != 0) { /* * If this view is becoming visible, invalidate it in case it changed while * it was not visible. Marking it drawn ensures that the invalidation will * go through. */ mPrivateFlags |= PFLAG_DRAWN; invalidate(true);
needGlobalAttributesUpdate(true);
// a view becoming visible is worth notifying the parent about in case nothing has // focus. Even if this specific view isn't focusable, it may contain something that // is, so let the root view try to give this focus if nothing else does. // 判断是否可需要通知矫正焦点1 shouldNotifyFocusableAvailable = hasSize(); } }
if ((changed & ENABLED_MASK) != 0) { if ((mViewFlags & ENABLED_MASK) == ENABLED) { // a view becoming enabled should notify the parent as long as the view is also // visible and the parent wasn't already notified by becoming visible during this // setFlags invocation. // 判断是否可需要通知矫正焦点2 shouldNotifyFocusableAvailable = canTakeFocus(); } else { if (isFocused()) clearFocus(); } }
publicvoidfocusableViewAvailable(View v){ if (mParent != null // shortcut: don't report a new focusable view if we block our descendants from // getting focus or if we're not visible && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS) && ((mViewFlags & VISIBILITY_MASK) == VISIBLE) && (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen()) // shortcut: don't report a new focusable view if we already are focused // (and we don't prefer our descendants) // // note: knowing that mFocused is non-null is not a good enough reason // to break the traversal since in that case we'd actually have to find // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and // an ancestor of v; this will get checked for at ViewAncestor && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) { // 一层一层向上传递 mParent.focusableViewAvailable(v); } }
publicvoidfocusableViewAvailable(View v){ checkThread(); if (mView != null) { if (!mView.hasFocus()) { // 如果视图树中没有一个View有焦点,则直接在传递来的View上获取焦点 if (sAlwaysAssignFocus || !mAttachInfo.mInTouchMode) { v.requestFocus(); } } else { // the one case where will transfer focus away from the current one // is if the current view is a view group that prefers to give focus // to its children first AND the view is a descendant of it. // 如果当前有焦点View View focused = mView.findFocus(); // 检查是否需要将焦点转移到这个View上 if (focused instanceof ViewGroup) { ViewGroup group = (ViewGroup) focused; // 如果当前焦点View是传递来的View的直接父View, // 并且焦点优先子获取View,则将焦点传递给v if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS && isViewDescendantOf(v, focused)) { v.requestFocus(); } } } } }