View View 是如何被添加到屏幕窗口上 当我们在调用 Activity#setContentView(int layoutResID)
时,实际上调用的是 PhoneWindow#setContentView(int layoutResID)
PhoneWindow
流程代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public void setContentView (int layoutResID) { installDecor(); mLayoutInflater.inflate(layoutResID, mContentParent); } private void installDecor () { if (mDecor == null ) { mDecor = generateDecor(-1 ); } else { mDecor.setWindow(this ); } if (mContentParent == null ) { mContentParent = generateLayout(mDecor); } } protected DecorView generateDecor (int featureId) { return new DecorView(context, featureId, this , getAttributes()); } protected ViewGroup generateLayout (DecorView decor) { mDecor.onResourcesLoaded(mLayoutInflater, layoutResource); ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); return contentParent; }
AppCompatActivity#setContentView(int resId)
兼容实际上调用的是 AppCompatDelegateImpl#setContentView(int resId)
AppCompatDelegateImpl
流程代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public void setContentView (int resId) { ensureSubDecor(); ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content); contentParent.removeAllViews(); LayoutInflater.from(mContext).inflate(resId, contentParent); mAppCompatWindowCallback.getWrapped().onContentChanged(); } private void ensureSubDecor () { if (!mSubDecorInstalled) { mSubDecor = createSubDecor(); } } private ViewGroup createSubDecor () { final ContentFrameLayout contentView = (ContentFrameLayout) subDecor.findViewById( R.id.action_bar_activity_content); final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content); if (windowContentView != null ) { windowContentView.setId(View.NO_ID); contentView.setId(android.R.id.content); } mWindow.setContentView(subDecor); return subDecor; }
View 的绘制流程
绘制入口
1 2 3 ActivityThread.handleResumeActivity --> WindowManagerImpl.addView() --> WindowManagerGlobal.addView() --> new ViewRootImpl()
绘制的类及方法
1 2 3 4 5 6 ViewRootImpl.setView() --> ViewRootImpl.requestLayout() --> ViewRootImpl.scheduleTraversals() --> ViewRootImpl.doTraversal() --> ViewRootImpl.performTraversals()
绘制三大步骤
1 2 3 测量:ViewRootImpl.performMeasure -> view.onMeasure -> view.setMeasuredDimension -> view.setMeasuredDimensionRaw 布局:ViewRootImpl.performLayout -> view.layout -> view.onLayout 绘制:ViewRootImpl.performDraw -> ViewRootImpl.draw -> ViewRootImpl.drawSoftware -> view.draw
Measure类型
EXACTLY:固定大小,父容器检测出子 View 的大小【match_parent、dp/px
】
AT_MOST:最大大小,父容器指定一个可用大小,View的大小不能超过该值【wrap_content】
UNSPECIFIED:不对 View 做任何限制,系统内部使用
childLayoutParams\parentSpecMode
EXACTLY
AT_MOST
UNSPECIFIED
dp/px
EXACTLY/childSize
EXACTLY/childSize
EXACTLY/childSize
match_parent
EXACTLY/parentSize
AT_MOST/parentSize
UNSPECIFIED/0
wrap_content
AT_MOST/parentSize
AT_MOST/parentSize
UNSPECIFIED/0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static int getDefaultSize (int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = size; break ; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break ; } return result; }
事件分发机制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 participant Activity participant PhoneWindow participant DecorView participant ViewGroup participant View Activity -> PhoneWindow:superDispatchTouchEvent() PhoneWindow -> DecorView:superDispatchTouchEvent() DecorView -> ViewGroup:dispatchTouchEvent() ViewGroup -> ViewGroup:onInterceptTouchEvent() ViewGroup -> View:onTouchEvent() View -> ViewGroup:return false ViewGroup -> DecorView:return false DecorView -> PhoneWindow:return false PhoneWindow -> Activity:return false Activity -> Activity:onTouchEvent()
dispatchTouchEvent
:是否分发
onInterceptTouchEvent
:是否拦截
onTouchEvent
:是否消费
事件分发流程 当屏幕被触摸,首先会通过硬件产生触摸事件传入内核,然后走到 FrameWork
层(具体流程感兴趣的可以看看参考链接),最后经过一系列事件处理到达ViewRootImpl
的 processPointerEvent
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 private int processPointerEvent (QueuedInputEvent q) { final MotionEvent event = (MotionEvent)q.mEvent; ... boolean handled = mView.dispatchPointerEvent(event); ... } public final boolean dispatchPointerEvent (MotionEvent event) { if (event.isTouchEvent()) { return dispatchTouchEvent(event); } else { return dispatchGenericMotionEvent(event); } } @Override public boolean dispatchTouchEvent (MotionEvent ev) { final Window.Callback cb = mWindow.getCallback(); return cb != null && !mWindow.isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super .dispatchTouchEvent(ev); } public boolean dispatchTouchEvent (MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true ; } return onTouchEvent(ev); } @Override public boolean superDispatchTouchEvent (MotionEvent event) { return mDecor.superDispatchTouchEvent(event); } public boolean superDispatchTouchEvent (MotionEvent event) { return super .dispatchTouchEvent(event); }
事件的分发流程就比较清楚了:
ViewRootImpl --> DecorView --> Activity --> PhoneWindow --> DecorView --> ViewGroup
这里绕来绕去主要原因在于解耦:
ViewRootImpl
并不知道有Activity这种东西存在,它只是持有了 DecorView
。所以先传给了 DecorView
,而 DecorView
知道有AC,所以传给了AC。
Activity
也不知道有 DecorView
,它只是持有 PhoneWindow
,所以这么一段调用链就形成了。