Activity:很熟悉了,我们所能见到页面,不过多阐述; PhoneWindow:继承于Window类,是Window的具体实现。在PhoneWindow中持有着一个很重要的View对象,DecorView。 DecorView:是所有窗口的根View,继承于FrameLayout,并对其进行扩展修饰,比如添加TitleBar等。 ① 在 Google 官方文档中是这么定义: 大概意思是:MeasureSpec 封装了从父View 传递给到子View的布局需求,每个MeasureSpec代表了view的宽度或高度的测量要求,即size(大小)和mode(模式)。 从子View的角度分析MeasureSpec的转化规则: view的绘制流程概括的描述为三部曲:measure -> layout -> draw Window的添加过程需要通过WindowManager的addView来实现。在addView时会创建一个ViewRootImpl对象,然后通过该对象可的setView完成Window的添加,在setView中调用requestLayout()完成异步刷新请求,在requestLayout中调用performTraversals来完场view的绘制。 作用:measure 主要功能就是测量设置 View 的大小。 onMeasure(这段代码就是measure过程的核心代码),接下来对onMeasure重点刨析: ①  onMeasure#getSuggestedMinimumWidth() 同理可得 onMeasure#getSuggestedMinimumHeight()。 ② onMeasure#getDefaultSize() getDefaultSize 的逻辑跟我们之前分析的 MeasureSpec 转化规则非常相似。就是根据specMode设置大小。 ③ onMeasure#setMeasuredDimension() 作用:确定ViewGroup和子View的位置 LayoutTransition是用于处理ViewGroup增加和删除子视图的动画效果,也就是说如果当前ViewGroup未添加LayoutTransition动画,或者LayoutTransition动画此刻并未运行,那么调用super.layout(l, t, r, b),即调用View的layout方法,否则将mLayoutCalledWhileSuppressed设置为true,等待动画完成时再调用requestLayout()。 首先通过调用setFrame方法来设定四个顶点的位置,接下来调用onLayout方法,用于确定子View的位置。然而在View和ViewGroup中,均没有真正实现onLayout,因为onLayout的实现在ViewGroup的各子类中,如下是LinearLayout和RelativeLayout的onLayout代码: ViewGroup子类的方法中原理大致相似,都是遍历所有子View,最后调用子View的layout方法来指定子View的位置。 Draw过程就相对更简单了,其作用是将View绘制到屏幕上面,其主要的绘制流程在如下源码中注释: 主要的绘制步骤总结如下:
一、基本概念:
1、Activity、Window、PhoneWindow、DecorView之间的关系:
 Window:每个Activity都包含一个Window,也可以说每个Activity都包含一个Window的对象。Window是一个抽象基类,是Activity和View的交互接口,且只有一个实现类PhoneWindow。我们可以将其理解为一个载体,各种View都在这个载体上显示。public class Activity extends ContextThemeWrappe{ private Window mWindow; } public class PhoneWindow extends Window{ private DecorView mDecor; } 2、MeasureSpc:
A MeasureSpec encapsulates the layout requirements passed from parent to child. Each MeasureSpec represents a requirement for either the width or the height. A MeasureSpec is comprised of a size and a mode. 
 ② MeasureSpc是一个32位的int值,高2位代表SpecMode(测量模式),低30位代表了SpecSize(测量大小)。
 ③ SpecMode分为三类:
 · unSpecified:父容器不对子View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量的状态。(可忽略)
 · Exactly:父容器已经测量出子View的大小。对应是view的LayoutParams的match_parent或者具体数值。
 · At_most:父容器指定了一个可用大小的SpecSize,view的大小不能够大于这个值,对应wrap_content。
 ④ 重点:View的MeasureSpec,由父 view 的MeasureSpec加上子 View 的自己的 LayoutParams,通过相应的规则转化,共同决定。
 从父View的角度分析MeasureSpec的转化规则:
 ①若子View宽/高为match_parent,则子View的SpecMode也是Exactly模式,且其大小是父容器的剩余空间。
 ②若子View宽/高为wrap_parent,则子View的SpecMode为At_most模式,且其大小不超过父容器的剩余空间。
 ③若子View宽/高为具体数值,则子View的SpecMode为Exactly模式,大小就是该具体数值。
 ①若子View宽/高为match_parent,则子View的SpecMode也是At_most模式,且其大小不超过父容器的剩余空间。
 ②若子View宽/高为wrap_parent,则子View的SpecMode为At_most模式,且其大小不超过父容器的剩余空间。
 ③若子View宽/高为固定宽高,则子View的SpecMode为Exactly模式,大小就是该固定宽高。
 ①若父容器的SpecMode为Exactly,那么子View的SpecMode也为Exactly,且其大小是父容器的剩余空间。
 ②若父容器的SpecMode为At_most,那么子View的SpecMode也为At_most,且其大小是父容器的剩余空间。二、流程概述 :
三、流程详述 :
1、ViewRootImpl (绘制入口):
 总结:WindowManagerImpl -> addView -> new ViewRootImpl -> setView -> requestLayout -> performTraversals
 绘制流程三部曲的核心入口就在 ViewRootImpl 类的 performTraversals() 方法中。private void performTraversals() { ...... int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); ......     mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); ......     mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight()); ......     mView.draw(canvas); ...... } 2、measure(测量):
 该过程由view的measure方法来完成,该方法是 final 类型,子类不能覆盖,在measure方法中会调用 onMeasure()方法,我们也可以复写 onMeasure()方法去测量设置 View 的大小。public final void measure(int widthMeasureSpec, int heightMeasureSpec) { ..... onMeasure(widthMeasureSpec, heightMeasureSpec); ..... } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension( getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec) ); } protected int getSuggestedMinimumWidth() { //返回View的建议最小宽度值,即xml布局中用设置的属性minWidth或背景大小。 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); } 
 作用:根据View的建议最小值,结合父View传递的measureSpec,返回SpecSize,而这个值基本就是view测量后的大小。public static int getDefaultSize(int size, int measureSpec) { int result = size; //获取父View传递过来的模式 int specMode = MeasureSpec.getMode(measureSpec); //获取父View传递过来的大小 int specSize = MeasureSpec.getSize(measureSpec);          switch (specMode) { case MeasureSpec.UNSPECIFIED:             result = size;//View的大小父View未定,设置为建议最小值  break; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY:             result = specSize; break; } return result; } 
 作用:保存测量好的宽跟高
 注意:在onMeasure中必须调用这个方法,不然就会抛出 IllegalStateException 异常。
 至此,View的measure的过程已经介绍完毕。
 注: ViewGroup(即父View)的measure过程:
 ViewGroup除了完成自己的measure的过程以外,还要遍历取调用子View的measure方法,各个子View再去递归执行这个过程,从而达到了测量目的。和View不同的是,ViewGroup是个抽象类,他的测量过程并没有像View一样,在onMeasure方法中做统一处理,而是由其子类(比如,LinearLayout、RelativeLayout等)各自实现或其内部方法measureChildren方法实现。在measureChildren方法中,遍历子View,调用measureChild方法,测量每个子View。在measureChild中,首先获取子View的LayoutParams,通过该值获取子View的WidthMeasureSpec和HeightMeasureSpec,最后调用每个子View的measure方法,将WidthMeasureSpec和HeightMeasureSpec作为参数传入,进行测量,这样又回到了上述View的绘制流程中。对于LinearLayout和RelativeLayout等ViewGroup的子类,其实现流程大致相同,也是遍历子View,然后调用各自内部相应的方法,进而调用子View的measure方法。3、layout(布局):
 对View进行布局排版,要从ViewGroup说起,ViewGroup的layout方法:public final void layout(int l, int t, int r, int b) { if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) { if (mTransition != null) {             mTransition.layoutChange(this); } super.layout(l, t, r, b); } else { // record the fact that we noop'd it; request layout when transition finishes         mLayoutCalledWhileSuppressed = true; } } public void layout(int l, int t, int r, int b) { ... boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);      if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { onLayout(changed, l, t, r, b);          if (shouldDrawRoundScrollbar()) { if(mRoundScrollbarRenderer == null) {                 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); } } else {             mRoundScrollbarRenderer = null; }          mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;          ListenerInfo li = mListenerInfo; if (li != null && li.mOnLayoutChangeListeners != null) {             ArrayList<OnLayoutChangeListener> listenersCopy = (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); int numListeners = listenersCopy.size(); for (int i = 0; i < numListeners; ++i) {                 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); } } } ... } //LinearLayout的onLayout方法 protected void onLayout(boolean changed, int l, int t, int r, int b) { if (mOrientation == VERTICAL) { layoutVertical(l, t, r, b); } else { layoutHorizontal(l, t, r, b); } }  //layoutVertical void layoutVertical(int left, int top, int right, int bottom) { ... final int count = getVirtualChildCount(); ... for (int i = 0; i < count; i++) { final View child = getVirtualChildAt(i); if (child == null) {             childTop += measureNullChild(i); } else if (child.getVisibility() != GONE) { final int childWidth = child.getMeasuredWidth(); final int childHeight = child.getMeasuredHeight();              final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();              int gravity = lp.gravity; if (gravity < 0) {                 gravity = minorGravity; } final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.CENTER_HORIZONTAL:                     childLeft = paddingLeft + ((childSpace - childWidth) / 2) + lp.leftMargin - lp.rightMargin; break;                  case Gravity.RIGHT:                     childLeft = childRight - childWidth - lp.rightMargin; break;                  case Gravity.LEFT: default:                     childLeft = paddingLeft + lp.leftMargin; break; }              if (hasDividerBeforeChildAt(i)) {                 childTop += mDividerHeight; }              childTop += lp.topMargin; setChildFrame(child, childLeft, childTop + getLocationOffset(child),                           childWidth, childHeight);             childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);              i += getChildrenSkipCount(child, i); } } }  //setChildFrame private void setChildFrame(View child, int left, int top, int width, int height) {     child.layout(left, top, left + width, top + height); } // RelativeLayout的onLayout方法 protected void onLayout(boolean changed, int l, int t, int r, int b) { //  The layout has actually already been performed and the positions //  cached.  Apply the cached values to the children. final int count = getChildCount();      for (int i = 0; i < count; i++) {         View child = getChildAt(i); if (child.getVisibility() != GONE) {             RelativeLayout.LayoutParams st = (RelativeLayout.LayoutParams) child.getLayoutParams();             child.layout(st.mLeft, st.mTop, st.mRight, st.mBottom); } } } 
 总结:View的layout过程较measure过程相对简单,首先ViewGroup的layout的方法会被调用,通过setFrame来确定父View的位置,然后调用onLayout来确定子View的布局,onLayout的具体实现在ViewGroup的子类中,遍历所有子View,最终调用子View的layout方法来确定自己的位置,这样一层层的传递下去,完成整个View树的layout过程。4、draw(绘制):
public void draw(Canvas canvas) { final int privateFlags = mPrivateFlags; final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);     mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; int saveCount; if (!dirtyOpaque) { // 绘制背景,如果需要。 drawBackground(canvas); }      final int viewFlags = mViewFlags; boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; if (!verticalEdges && !horizontalEdges) { // 绘制自己 if (!dirtyOpaque) onDraw(canvas);          // 绘制子View dispatchDraw(canvas);          drawAutofilledHighlight(canvas);          if (mOverlay != null && !mOverlay.isEmpty()) {             mOverlay.getOverlayView().dispatchDraw(canvas); }          // 绘制装饰 onDrawForeground(canvas);          drawDefaultFocusHighlight(canvas);          if (debugDraw()) { debugDrawFocus(canvas); }          // we're done... return; } ... } 
 1.绘制背景 (drawBackground(canvas))
 2.绘制自己 (onDraw(canvas);自定义View的绘制在这里进行,该方法是一个空方法,具体实现在View的继承类中,自己复写实现内容绘制)
 3.绘制子View (dispatchDraw(canvas))
 4.绘制装饰 (onDrawForeground(canvas); 如ScrollBar等)
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算
官方软件产品操作指南 (170)