深入焦点处理流程
来源:互联网 发布:m2m 数据采集 编辑:程序博客网 时间:2024/06/04 01:05
深入焦点处理流程
0.开始响应按键
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { /** * Delivers post-ime input events to the view hierarchy. */ final class ViewPostImeInputStage extends InputStage { public ViewPostImeInputStage(InputStage next) { super(next); } //入口方法 private int processKeyEvent(QueuedInputEvent q) { final KeyEvent event = (KeyEvent)q.mEvent; // 1.先去执行mView的dispatchKeyEvent // Deliver the key to the view hierarchy. if (mView.dispatchKeyEvent(event)) { return FINISH_HANDLED; } //... // Handle automatic focus changes. if (event.getAction() == KeyEvent.ACTION_DOWN) { if (direction != 0) { //2.找到当前获取焦点的view View focused = mView.findFocus(); if (focused != null) { //3.之后通过‘当前焦点的view’和‘方向’,寻找下一个焦点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.尝试让下一个焦点view,获取焦点 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; } }}
1.先去执行mView的dispatchKeyEvent
// Deliver the key to the view hierarchy.if (mView.dispatchKeyEvent(event)) { return FINISH_HANDLED;}
2.找到当前获取焦点的view
/*** Find the view in the hierarchy rooted at this view that currently has* focus.** @return The view that currently has focus, or null if no focused view can* be found.*/View focused = mView.findFocus();
3.之后通过‘当前焦点的view’和‘方向’,寻找下一个焦点view
/*** Find the nearest view in the specified direction that can take focus.* This does not actually give focus to that view.** @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT** @return The nearest focusable in the specified direction, or null if none* can be found.*/View v = focused.focusSearch(direction)
4.尝试让下一个焦点view,获取焦点
/*** Call this to try to give focus to a specific view or to one of its* descendants.** A view will not actually take focus if it is not focusable ({@link #isFocusable} returns* false), or if it is focusable and it is not focusable in touch mode* ({@link #isFocusableInTouchMode}) while the device is in touch mode.** See also {@link #focusSearch(int)}, which is what you call to say that you* have focus, and you want your parent to look for the next one.** This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments* {@link #FOCUS_DOWN} and <code>null</code>.** @return Whether this view or one of its descendants actually took focus.*/v.requestFocus(direction, mTempRect)
1.dispatchKeyEvent()
1.mView.dispatchKeyEvent(event)
2.activity.dispatchKeyEvent
3.win.superDispatchKeyEvent
4.mDecor.superDispatchKeyEvent
5.framelayout.dispatchKeyEvent
6.view.dispatchKeyEvent
7.event.dispatch
8.view.onKeyUp
9.view.performClick
2.findFocus()
1.viewGroup.findFocus
2.view.findFocus
3.focusSearch()
1.view.focusSearch(direction)
2.mParent.focusSearch(this, direction);
3.FocusFinder.getInstance().findNextFocus(this, focused, direction);
4.requestFocus(direction, mTempRect)
1.viewGroup.requestFocus
//FOCUS_BEFORE_DESCENDANTS默认值public abstract class ViewGroup extends View implements ViewParent, ViewManager public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initViewGroup(); initFromAttributes(context, attrs, defStyleAttr, defStyleRes); } private void initViewGroup() { // ViewGroup doesn't draw by default if (!debugDraw()) { setFlags(WILL_NOT_DRAW, DRAW_MASK); } mGroupFlags |= FLAG_CLIP_CHILDREN; mGroupFlags |= FLAG_CLIP_TO_PADDING; mGroupFlags |= FLAG_ANIMATION_DONE; mGroupFlags |= FLAG_ANIMATION_CACHE; mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE; if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) { mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS; } setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS); mChildren = new View[ARRAY_INITIAL_CAPACITY]; mChildrenCount = 0; mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE; } public boolean requestFocus(int direction, Rect previouslyFocusedRect) { if (DBG) { System.out.println(this + " ViewGroup.requestFocus direction=" + direction); } int descendantFocusability = getDescendantFocusability(); switch (descendantFocusability) { case FOCUS_BLOCK_DESCENDANTS: return super.requestFocus(direction, previouslyFocusedRect); case FOCUS_BEFORE_DESCENDANTS: { final boolean took = super.requestFocus(direction, previouslyFocusedRect); return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect); } 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); } }}
2.viewGroup.onRequestFocusInDescendants()
public abstract class ViewGroup extends View implements ViewParent, ViewManager { protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { int index; int increment; int end; int count = mChildrenCount; if ((direction & FOCUS_FORWARD) != 0) { index = 0; increment = 1; end = count; } else { index = count - 1; increment = -1; end = -1; } final View[] children = mChildren; for (int i = index; i != end; i += increment) { View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { if (child.requestFocus(direction, previouslyFocusedRect)) { return true; } } } return false; }}
/*** Use with {@link #focusSearch(int)}. Move focus to the previous selectable* item.*/public static final int FOCUS_BACKWARD = 0x00000001;/*** Use with {@link #focusSearch(int)}. Move focus to the next selectable* item.*/public static final int FOCUS_FORWARD = 0x00000002;/*** Use with {@link #focusSearch(int)}. Move focus to the left.*/public static final int FOCUS_LEFT = 0x00000011;/*** Use with {@link #focusSearch(int)}. Move focus up.*/public static final int FOCUS_UP = 0x00000021;/*** Use with {@link #focusSearch(int)}. Move focus to the right.*/public static final int FOCUS_RIGHT = 0x00000042;/*** Use with {@link #focusSearch(int)}. Move focus down.*/public static final int FOCUS_DOWN = 0x00000082;
3.view.requestFocus
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { public final boolean requestFocus(int direction) { return requestFocus(direction, null); } public boolean requestFocus(int direction, Rect previouslyFocusedRect) { return requestFocusNoSearch(direction, previouslyFocusedRect); } private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { // need to be focusable if ((mViewFlags & FOCUSABLE_MASK) != 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 if (hasAncestorThatBlocksDescendantFocus()) { return false; } handleFocusGainInternal(direction, previouslyFocusedRect); return true; }}
突破口
1.focusFinder.findNextUserSpecifiedFocus()
public void setNextFocusUpId(int nextFocusUpId) { mNextFocusUpId = nextFocusUpId;}public void setNextFocusDownId(int nextFocusDownId) { mNextFocusDownId = nextFocusDownId;}public void setNextFocusLeftId(int nextFocusLeftId) { mNextFocusLeftId = nextFocusLeftId;}public void setNextFocusRightId(int nextFocusRightId) { mNextFocusRightId = nextFocusRightId;}
2.viewgroup.focusSearch(int direction)
@Overridepublic View focusSearch(int direction) { if (direction == View.FOCUS_LEFT) { View view = getRootView(); VerticalViewPager viewPager = (VerticalViewPager) view.findViewById(R.id.view_pager); int currentItem = viewPager.getCurrentItem(); ViewGroup headerView = (ViewGroup) view.findViewById(R.id.header_view); return headerView.getChildAt(currentItem); } else { return super.focusSearch(direction); }}
3.viewgroup.focusSearch(View focused, int direction)
@Overridepublic View focusSearch(View focused, int direction) { final FocusFinder ff = FocusFinder.getInstance(); View result = ff.findNextFocus(this, focused, direction); if (result == null) { if (direction == View.FOCUS_LEFT) { View view = getRootView(); VerticalViewPager viewPager = (VerticalViewPager) view.findViewById(R.id.view_pager); int currentItem = viewPager.getCurrentItem(); ViewGroup headerView = (ViewGroup) view.findViewById(R.id.header_view); return headerView.getChildAt(currentItem); } else { return focused; } } else { return result; }}
4.viewGroup.requestFocus()
@Overridepublic boolean requestFocus(int direction, Rect previouslyFocusedRect) { if (getChildCount() == 0) { return false; } return super.requestFocus(direction, previouslyFocusedRect);}
5.viewGroup.onRequestFocusInDescendants()
@Overrideprotected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { View preFocusedView = getLastChildFocusedView(); View view = preFocusedView != null ? preFocusedView : getChildAt(0); return view.requestFocus();}
6.viewGroup.dispatchKeyEvent() 返回true,就停止焦点处理
@Overridepublic boolean dispatchKeyEvent(KeyEvent event) { return super.dispatchKeyEvent(event) || executeKeyEvent(event);}private boolean executeKeyEvent(KeyEvent event) { boolean handled = false; if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_LEFT: break; } }}
7.viewGroup.addOnLayoutChangeListener()
//第一种写法//当使用这种写法的流程//1.第一个pager获取焦点//2.由于第一个pager没有内容,焦点跑到第一个radiobutton上(导航tab)viewPager.requestFocus();//2.第二中写法ViewUtil.addGlobalLayoutListenerOnce(viewPager, new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { viewPager.requestFocus(); } });
8.发现目标的view没有正确获取焦点
1.第一步检查是否成功 view.requestFocus()
2.延时获取activity.getCurrentFocus()
3.debug上一步的view,调用栈。
参考
Android View框架总结(二)View焦点(http://blog.csdn.net/hejjunlin/article/details/52263256)
从源码出发浅析Android TV的焦点移动原理-上篇(http://mp.weixin.qq.com/s/hBWa9q3SP8LCWE_ER3FnaQ)
从源码出发浅析Android TV的焦点移动原理-下篇(http://mp.weixin.qq.com/s/ghT_2uKn5v6MgaRq1lfmrA)
阅读全文
1 0
- 深入焦点处理流程
- 焦点处理
- 深入理解Redis:命令处理流程
- android 焦点获取流程
- 深入理解组策略一:组策略处理流程
- [转载]深入理解组策略一:组策略处理流程
- 焦点图触屏划动处理
- 焦点处理事件
- IP处理焦点项目
- 处理焦点项目2
- 音频焦点处理
- 焦点冲突处理例子
- EditText的焦点处理
- jq焦点处理
- editext焦点获取处理
- WebKit焦点切换的流程
- Android焦点分发基本流程
- 5.处理自定义控件焦点
- 服务器:硬RAID与软RAID的区别
- 前端校招面试的一些经验(阿里美团爱奇艺)
- 回溯法求和 算法设计
- Elasticsearch基础教程
- 自定义折线图
- 深入焦点处理流程
- mybatis之jdbc的问题
- lintcode--Expression Expand
- 无题
- mybatis中@Param的用法和作用
- 图像的平移和缩放
- normalize、splitText
- 关于RecyclerView中含有CheckBox,Button等控件失去焦点的解决办法
- pip install --upgrade pip 9.0.1 error