1.View的绘制流程分几步,从哪开始?哪个过程结束以后能看到view?

答:从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程。draw流程结束以后就可以在屏幕上看到view了。

2.view的测量宽高和实际宽高有区别吗?

答:基本上百分之99的情况下都是可以认为没有区别的。有两种情况,有区别。第一种 就是有的时候会因为某些原因 view会多次测量,那第一次测量的宽高 肯定和最后实际的宽高 是不一定相等的,但是在这种情况下

最后一次测量的宽高和实际宽高是一致的。此外,实际宽高是在layout流程里确定的,我们可以在layout流程里 将实际宽高写死 写成硬编码,这样测量的宽高和实际宽高就肯定不一样了,虽然这么做没有意义 而且也不好。

3.view的measureSpec 由谁决定?顶级view呢?

答:由view自己的layoutparams和父容器  一起决定自己的measureSpec。一旦确定了spec,onMeasure中就可以确定view的宽高了。

顶级view就稍微特殊一点,对于decorView的测量在ViewRootImpl的源码里。

  1.  
  2. //desire的这2个参数就代表屏幕的宽高,
  3. childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
  4. childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
  5. performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
  6.  
  7. //decorView的measureSpec就是在这里确定的,其实比普通view的measurespec要简单的多
  8. //代码就不分析了 一目了然的东西
  9. private static int getRootMeasureSpec(int windowSize, int rootDimension) {
  10. int measureSpec;
  11. switch (rootDimension) {
  12.  
  13. case ViewGroup.LayoutParams.MATCH_PARENT:
  14. // Window can't resize. Force root view to be windowSize.
  15. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
  16. break;
  17. case ViewGroup.LayoutParams.WRAP_CONTENT:
  18. // Window can resize. Set max size for root view.
  19. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
  20. break;
  21. default:
  22. // Window wants to be an exact size. Force root view to be that size.
  23. measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
  24. break;
  25. }
  26. return measureSpec;
  27. }

4.对于普通view来说,他的measure过程中,与父view有关吗?如果有关,这个父view也就是viewgroup扮演了什么角色?

答:看源码:

  1. //对于普通view的measure来说 是由这个view的 父view ,也就是viewgroup来触发的。
  2. //也就是下面这个measureChildWithMargins方法
  3.  
  4. protected void measureChildWithMargins(View child,
  5. int parentWidthMeasureSpec, int widthUsed,
  6. int parentHeightMeasureSpec, int heightUsed) {
  7. //第一步 先取得子view的 layoutParams 参数值
  8. final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
  9.  
  10. //然后开始计算子view的spec的值,注意这里看到 计算的时候除了要用子view的 layoutparams参数以外
  11. //还用到了父view 也就是viewgroup自己的spec的值
  12. final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
  13. mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
  14. + widthUsed, lp.width);
  15. final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
  16. mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
  17. + heightUsed, lp.height);
  18.  
  19. child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
  20. }
  21.  
  22. //这个算view的spec的方法 看上去一大串 但是真的逻辑非常简单 就是根据父亲viewgroup
  23. //的meaurespec 同时还有view自己的params来确定 view自己的measureSpec。
  24. //注意这里的参数是padding,这个值的含义是 父容器已占用的控件的大小 所以view的Specsize
  25. //的值 你们可以看到 是要减去这个padding的值的。总大小-已经用的 =可用的。 很好理解。
  26.  
  27. //然后就是下面的switch逻辑 要自己梳理清楚。其实也不难,主要是下面几条原则
  28. //如果view采用固定宽高,也就是写死的数值那种。那就不管父亲的spec的值了,view的spec 就肯定是exactly 并且大小遵循layout参数里设置的大小。
  29.  
  30. //如果view的宽高是match_parent ,那么就要看父容器viewgroup的 spec的值了,如果父view的spec是exactly模式,
  31. //那view也肯定是exactly,并且大小就是父容器剩下的空间。如果父容器是at_most模式,那view也是at_most 并且不会超过剩余空间大小
  32.  
  33. //如果view的宽高是wrap_content, 那就不管父容器的spec了,view的spec一定是at_most 并且不会超过父view 剩余空间的大小。
  34.  
  35. public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
  36. int specMode = MeasureSpec.getMode(spec);
  37. int specSize = MeasureSpec.getSize(spec);
  38.  
  39. int size = Math.max(0, specSize - padding);
  40.  
  41. int resultSize = 0;
  42. int resultMode = 0;
  43.  
  44. switch (specMode) {
  45. // Parent has imposed an exact size on us
  46. case MeasureSpec.EXACTLY:
  47. if (childDimension >= 0) {
  48. resultSize = childDimension;
  49. resultMode = MeasureSpec.EXACTLY;
  50. } else if (childDimension == LayoutParams.MATCH_PARENT) {
  51. // Child wants to be our size. So be it.
  52. resultSize = size;
  53. resultMode = MeasureSpec.EXACTLY;
  54. } else if (childDimension == LayoutParams.WRAP_CONTENT) {
  55. // Child wants to determine its own size. It can't be
  56. // bigger than us.
  57. resultSize = size;
  58. resultMode = MeasureSpec.AT_MOST;
  59. }
  60. break;
  61.  
  62. // Parent has imposed a maximum size on us
  63. case MeasureSpec.AT_MOST:
  64. if (childDimension >= 0) {
  65. // Child wants a specific size... so be it
  66. resultSize = childDimension;
  67. resultMode = MeasureSpec.EXACTLY;
  68. } else if (childDimension == LayoutParams.MATCH_PARENT) {
  69. // Child wants to be our size, but our size is not fixed.
  70. // Constrain child to not be bigger than us.
  71. resultSize = size;
  72. resultMode = MeasureSpec.AT_MOST;
  73. } else if (childDimension == LayoutParams.WRAP_CONTENT) {
  74. // Child wants to determine its own size. It can't be
  75. // bigger than us.
  76. resultSize = size;
  77. resultMode = MeasureSpec.AT_MOST;
  78. }
  79. break;
  80.  
  81. // Parent asked to see how big we want to be
  82. case MeasureSpec.UNSPECIFIED:
  83. if (childDimension >= 0) {
  84. // Child wants a specific size... let him have it
  85. resultSize = childDimension;
  86. resultMode = MeasureSpec.EXACTLY;
  87. } else if (childDimension == LayoutParams.MATCH_PARENT) {
  88. // Child wants to be our size... find out how big it should
  89. // be
  90. resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
  91. resultMode = MeasureSpec.UNSPECIFIED;
  92. } else if (childDimension == LayoutParams.WRAP_CONTENT) {
  93. // Child wants to determine its own size.... find out how
  94. // big it should be
  95. resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
  96. resultMode = MeasureSpec.UNSPECIFIED;
  97. }
  98. break;
  99. }
  100. return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
  101. }

5.view的meaure和onMeasure有什么关系?

答:看源码:

  1. //view的measure是final 方法 我们子类无法修改的。
  2. public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
  3. boolean optical = isLayoutModeOptical(this);
  4. if (optical != isLayoutModeOptical(mParent)) {
  5. Insets insets = getOpticalInsets();
  6. int oWidth = insets.left + insets.right;
  7. int oHeight = insets.top + insets.bottom;
  8. widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth);
  9. heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight);
  10. }
  11.  
  12. // Suppress sign extension for the low bytes
  13. long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
  14. if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);
  15.  
  16. if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
  17. widthMeasureSpec != mOldWidthMeasureSpec ||
  18. heightMeasureSpec != mOldHeightMeasureSpec) {
  19.  
  20. // first clears the measured dimension flag
  21. mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
  22.  
  23. resolveRtlPropertiesIfNeeded();
  24.  
  25. int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
  26. mMeasureCache.indexOfKey(key);
  27. if (cacheIndex < 0 || sIgnoreMeasureCache) {
  28. // measure ourselves, this should set the measured dimension flag back
  29. onMeasure(widthMeasureSpec, heightMeasureSpec);
  30. mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
  31. } else {
  32. long value = mMeasureCache.valueAt(cacheIndex);
  33. // Casting a long to int drops the high 32 bits, no mask needed
  34. setMeasuredDimensionRaw((int) (value >> 32), (int) value);
  35. mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
  36. }
  37.  
  38. // flag not set, setMeasuredDimension() was not invoked, we raise
  39. // an exception to warn the developer
  40. if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {
  41. throw new IllegalStateException("View with id " + getId() + ": "
  42. + getClass().getName() + "#onMeasure() did not set the"
  43. + " measured dimension by calling"
  44. + " setMeasuredDimension()");
  45. }
  46.  
  47. mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
  48. }
  49.  
  50. mOldWidthMeasureSpec = widthMeasureSpec;
  51. mOldHeightMeasureSpec = heightMeasureSpec;
  52.  
  53. mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |
  54. (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
  55. }
  56.  
  57. //不过可以看到的是在measure方法里调用了onMeasure方法
  58. //所以就能知道 我们在自定义view的时候一定是重写这个方法!
  59. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  60. setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
  61. getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
  62. }

6.简要分析view的measure流程?

答:先回顾问题4,viewgroup 算出子view的spec以后 会调用子view的measure方法,而子view的measure方法 我们问题5也看过了实际上是调用的onMeasure方法

所以我们只要分析好onMeasure方法即可,注意onMeasure方法的参数 正是他的父view算出来的那2个spec的值(这里view的measure方法会把这个spec里的specSize值做略微的修改 这个部分 不做分析 因为measure方法修改specSize的部分很简单)。

  1. //可以看出来这个就是setMeasuredDimension方法的调用 这个方法看名字就知道就是确定view的测量宽高的
  2. //所以我们分析的重点就是看这个getDefaultSize 方法 是怎么确定view的测量宽高的
  3. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  4. setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
  5. getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
  6. }
  7.  
  8. //这个方法特别简单 基本可以认为就是近似的返回spec中的specSize,除非你的specMode是UNSPECIFIED
  9. //UNSPECIFIED 这个一般都是系统内部测量才用的到,这种时候返回size 也就是getSuggestedMinimumWidth的返回值
  10. public static int getDefaultSize(int size, int measureSpec) {
  11. int result = size;
  12. int specMode = MeasureSpec.getMode(measureSpec);
  13. int specSize = MeasureSpec.getSize(measureSpec);
  14.  
  15. switch (specMode) {
  16. case MeasureSpec.UNSPECIFIED:
  17. result = size;
  18. break;
  19. case MeasureSpec.AT_MOST:
  20. case MeasureSpec.EXACTLY:
  21. result = specSize;
  22. break;
  23. }
  24. return result;
  25. }
  26.  
  27. //跟view的背景相关 这里不多做分析了
  28. protected int getSuggestedMinimumWidth() {
  29. return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
  30. }

7.自定义view中 如果onMeasure方法 没有对wrap_content 做处理 会发生什么?为什么?怎么解决?

答:如果没有对wrap_content做处理 ,那即使你在xml里设置为wrap_content.其效果也和match_parent相同。看问题4的分析。我们可以知道view自己的layout为wrap,那mode就是at_most(不管父亲view是什么specmode).

这种模式下宽高就是等于specSize(getDefaultSize函数分析可知),而这里的specSize显然就是parentSize的大小。也就是父容器剩余的大小。那不就和我们直接设置成match_parent是一样的效果了么?

解决方式就是在onMeasure里 针对wrap 来做特殊处理 比如指定一个默认的宽高,当发现是wrap_content 就设置这个默认宽高即可。

8.ViewGroup有onMeasure方法吗?为什么?

答:没有,这个方法是交给子类自己实现的。不同的viewgroup子类 肯定布局都不一样,那onMeasure索性就全部交给他们自己实现好了。

9.为什么在activity的生命周期里无法获得测量宽高?有什么方法可以解决这个问题吗?

答:因为measure的过程和activity的生命周期  没有任何关系。你无法确定在哪个生命周期执行完毕以后 view的measure过程一定走完。可以尝试如下几种方法 获取view的测量宽高。

  1. //重写activity的这个方法
  2. public void onWindowFocusChanged(boolean hasFocus) {
  3. super.onWindowFocusChanged(hasFocus);
  4. if (hasFocus) {
  5. int width = tv.getMeasuredWidth();
  6. int height = tv.getMeasuredHeight();
  7. Log.v("burning", "width==" + width);
  8. Log.v("burning", "height==" + height);
  9.  
  10. }
  11. }

或者重写这个方法

  1. @Override
  2. protected void onStart() {
  3. super.onStart();
  4. tv.post(new Runnable() {
  5. @Override
  6. public void run() {
  7. int width = tv.getMeasuredWidth();
  8. int height = tv.getMeasuredHeight();
  9. }
  10. });
  11. }

再或者:

  1. @Override
  2. protected void onStart() {
  3. super.onStart();
  4. ViewTreeObserver observer = tv.getViewTreeObserver();
  5. observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  6. @Override
  7. public void onGlobalLayout() {
  8. int width = tv.getMeasuredWidth();
  9. int height = tv.getMeasuredHeight();
  10. tv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
  11. }
  12. });
  13. }

10.layout和onLayout方法有什么区别?

答:layout是确定本身view的位置 而onLayout是确定所有子元素的位置。layout里面 就是通过serFrame方法设设定本身view的 四个顶点的位置。这4个位置以确定 自己view的位置就固定了

然后就调用onLayout来确定子元素的位置。view和viewgroup的onlayout方法都没有写。都留给我们自己给子元素布局

11.draw方法 大概有几个步骤?

答: 一共是4个步骤, 绘制背景---------绘制自己--------绘制chrildren----绘制装饰。

12.setWillNotDraw方法有什么用?

答:这个方法在view里。

  1. /**
  2. * If this view doesn't do any drawing on its own, set this flag to
  3. * allow further optimizations. By default, this flag is not set on
  4. * View, but could be set on some View subclasses such as ViewGroup.
  5. *
  6. * Typically, if you override {@link #onDraw(android.graphics.Canvas)}
  7. * you should clear this flag.
  8. *
  9. * @param willNotDraw whether or not this View draw on its own
  10. */
  11. public void setWillNotDraw(boolean willNotDraw) {
  12. setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
  13. }

用于设置标志位的 也就是说 如果你的自定义view 不需要draw的话,就可以设置这个方法为true。这样系统知道你这个view 不需要draw 可以优化执行速度。viewgroup 一般都默认设置这个为true,因为viewgroup多数都是只负责布局

不负责draw的。而view 这个标志位 默认一般都是关闭的。

13.自定义view 有哪些需要注意的点?

答:主要是要处理wrap_content 和padding。否则xml 那边设置这2个属性就根本没用了。还有不要在view中使用handler 因为人家已经提供了post方法。如果是继承自viewGroup,那在onMeasure和onLayout里面 也要考虑

padding和layout的影响。也就是说specSize 要算一下 。最后就是如果view的动画或者线程需要停止,可以考虑在onDetachedFromWindow里面来做。

针对上述的几点,给出几个简单的自定义view 供大家理解。

给出一个圆形的view 范例:

  1. package com.example.administrator.motioneventtest;
  2.  
  3. import android.content.Context;
  4. import android.graphics.Canvas;
  5. import android.graphics.Color;
  6. import android.graphics.Paint;
  7. import android.util.AttributeSet;
  8. import android.view.View;
  9.  
  10. /**
  11. * Created by Administrator on 2016/2/4.
  12. */
  13. public class CircleView extends View {
  14.  
  15. private int mColor = Color.RED;
  16. private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  17.  
  18. private void init() {
  19. mPaint.setColor(mColor);
  20. }
  21.  
  22. @Override
  23. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  24. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  25. int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
  26. int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
  27. int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
  28. int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
  29.  
  30. //处理为wrap_content时的情况
  31. if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
  32. setMeasuredDimension(200, 200);
  33. } else if (widthSpecMode == MeasureSpec.AT_MOST) {
  34. setMeasuredDimension(200, heightSpecSize);
  35. } else if (heightSpecMode == MeasureSpec.AT_MOST) {
  36. setMeasuredDimension(widthSpecSize, 200);
  37. }
  38.  
  39. }
  40.  
  41. @Override
  42. protected void onDraw(Canvas canvas) {
  43. super.onDraw(canvas);
  44. //处理padding的情况
  45. final int paddingLeft = getPaddingLeft();
  46. final int paddingRight = getPaddingRight();
  47. final int paddingTop = getPaddingTop();
  48. final int paddingBottom = getPaddingBottom();
  49.  
  50. int width = getWidth() - paddingLeft - paddingRight;
  51. int height = getHeight() - paddingTop - paddingBottom;
  52. int radius = Math.min(width, height) / 2;
  53. canvas.drawCircle(paddingLeft + width / 2, paddingTop + height / 2, radius, mPaint);
  54. }
  55.  
  56. public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
  57. super(context, attrs, defStyleAttr);
  58. init();
  59. }
  60.  
  61. public CircleView(Context context) {
  62. super(context);
  63. init();
  64.  
  65. }
  66.  
  67. public CircleView(Context context, AttributeSet attrs) {
  68. super(context, attrs);
  69. init();
  70. }
  71. }

然后下面再给出一个范例,稍微复杂一点是自定义viewgroup了(主要是加强对onMeasure和onLayout的理解), 需求如下:

一个水平的viewgroup,内部的子元素 为了简单 我们假定他们的宽高都是一样的。来写一个这样的简单的viewgroup。

  1. package com.example.administrator.motioneventtest;
  2.  
  3. import android.content.Context;
  4. import android.util.AttributeSet;
  5. import android.util.Log;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8.  
  9. /**
  10. * Created by Administrator on 2016/2/4.
  11. */
  12. //这里我们只处理了padding的状态 没有处理margin的状态,子view的margin 对measure和layout的影响
  13. //就留给读者自己完成了
  14. public class CustomHorizontalLayout extends ViewGroup {
  15.  
  16. //设置默认的控件最小是多少 这里不提供自定义属性了 写死在代码里 你们可以自行拓展
  17. final int minHeight = 0;
  18. final int minWidth = 0;
  19.  
  20. public CustomHorizontalLayout(Context context) {
  21. super(context);
  22. }
  23.  
  24. public CustomHorizontalLayout(Context context, AttributeSet attrs) {
  25. super(context, attrs);
  26. }
  27.  
  28. public CustomHorizontalLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  29. super(context, attrs, defStyleAttr);
  30. }
  31.  
  32. @Override
  33. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  34. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  35. int measureWidth = 0;
  36. int measureHeight = 0;
  37. final int childCount = getChildCount();
  38. measureChildren(widthMeasureSpec, heightMeasureSpec);
  39. int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
  40. int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
  41. int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
  42. int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
  43. final View childView = getChildAt(0);
  44. final int paddingLeft = getPaddingLeft();
  45. final int paddingRight = getPaddingRight();
  46. final int paddingTop = getPaddingTop();
  47. final int paddingBottom = getPaddingBottom();
  48. //没有子控件 时 我们的宽高要作特殊处理
  49. if (childCount == 0) {
  50. //当没有子控件时,如果长宽有一个为wrap 那么就让这个控件以最小的形式展现
  51. //这里我们最小设置为0
  52. if (widthSpecMode == MeasureSpec.AT_MOST || heightSpecMode == MeasureSpec.AT_MOST) {
  53. setMeasuredDimension(minWidth, minHeight);
  54. } else {
  55. //否则根据我们的layout属性来
  56. setMeasuredDimension(getLayoutParams().width, getLayoutParams().height);
  57. }
  58.  
  59. } else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
  60. measureWidth = childView.getMeasuredWidth() * childCount;
  61. measureHeight = childView.getMeasuredHeight();
  62. setMeasuredDimension(paddingLeft + measureWidth + paddingRight, paddingTop + measureHeight + paddingBottom);
  63. } else if (heightSpecMode == MeasureSpec.AT_MOST) {
  64. measureHeight = childView.getMeasuredHeight();
  65. setMeasuredDimension(paddingLeft + paddingRight + widthSpecSize, paddingTop + paddingBottom + measureHeight);
  66. } else if (widthSpecMode == MeasureSpec.AT_MOST) {
  67. measureWidth = childView.getMeasuredWidth() * childCount;
  68. setMeasuredDimension(paddingLeft + paddingRight + measureWidth, paddingTop + paddingBottom + heightSpecSize);
  69. }
  70. }
  71.  
  72. @Override
  73. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  74. final int paddingLeft = getPaddingLeft();
  75. final int paddingRight = getPaddingRight();
  76. final int paddingTop = getPaddingTop();
  77. final int paddingBottom = getPaddingBottom();
  78. //左边初始位置为0
  79. int childLeft = 0 + paddingLeft;
  80. final int childCount = getChildCount();
  81. for (int i = 0; i < childCount; i++) {
  82. final View childView = getChildAt(i);
  83. if (childView.getVisibility() != View.GONE) {
  84. final int childWidth = childView.getMeasuredWidth();
  85. childView.layout(childLeft, 0 + paddingTop, childLeft + childWidth, paddingTop + childView.getMeasuredHeight());
  86. childLeft += childWidth;
  87. }
  88. }
  89. }
  90. }

Android View绘制13问13答的更多相关文章

  1. 简单研究Android View绘制三 布局过程

    2015-07-28 17:29:19 这一篇主要看看布局过程 一.布局过程肯定要不可避免的涉及到layout()和onLayout()方法,这两个方法都是定义在View.java中,源码如下: /* ...

  2. 简单研究Android View绘制一 测量过程

    2015-07-27 16:52:58 一.如何通过继承ViewGroup来实现自定义View?首先得搞清楚Android时如何绘制View的,参考Android官方文档:How Android Dr ...

  3. Android 多进程编程 15问15答!

    ps:阅读本文 需要对android 多进程编程有一定了解. 1.Android中总共有几种方式进行IPC? 答:一共有两种,一种是binder 还有一种是socket.Binder 大家用的比较多. ...

  4. Android View绘制原理分析

    推荐两篇分析view绘制原理比较好的文章,感谢作者的分享. <Android应用层View绘制流程与源码分析> <View 绘制流程>

  5. Android View绘制过程

    Android的View绘制是从根节点(Activity是DecorView)开始,他是一个自上而下的过程.View的绘制经历三个过程:Measure.Layout.Draw.基本流程如下图: per ...

  6. Android View绘制流程

    框架分析 在之前的下拉刷新中,小结过触屏消息先到WindowManagerService(Wms)然后顺次传递给ViewRoot(派生自Handler),经decor view到Activity再传递 ...

  7. Android View 绘制过程

    Android的View绘制是从根节点(Activity是DecorView)开始,他是一个自上而下的过程.View的绘制经历三个过程:Measure.Layout.Draw.基本流程如下图: per ...

  8. Android View 绘制刷新流程分析

    Android中对View的更新有很多种方式,使用时要区分不同的应用场合.1.不使用多线程和双缓冲      这种情况最简单,一般只是希望在View发生改变时对UI进行重绘.你只需显式地调用View对 ...

  9. Android View 绘制流程(Draw) 完全解析

    前言 前几篇文章,笔者分别讲述了DecorView,measure,layout流程等,接下来将详细分析三大工作流程的最后一个流程——绘制流程.测量流程决定了View的大小,布局流程决定了View的位 ...

随机推荐

  1. NPOI之Excel——合并单元格、设置样式、输入公式

    首先建立一个空白的工作簿用作测试,并在其中建立空白工作表,在表中建立空白行,在行中建立单元格,并填入内容: //建立空白工作簿 IWorkbook workbook = new HSSFWorkboo ...

  2. 如何精通java技术

    如何精通java技术 | 浏览:173 | 更新:2013-05-15 14:42 | 标签:java 对于一个程序员来说,精通JAVA可以说是他们的最高境界了.那么对于JAVA程序员来说,怎么才能精 ...

  3. PageLayoutControl的基本操作

    整理了下对PageLayoutControl的基本功能操作 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 2 ...

  4. Swagger PHP使用指南

    先说什么是Swagger, Swagger的使用目的是方便优美的呈现出接口API的各种定义, 生成API文档, 包括参数, 路径之类. 有时后端改了API的参数或者其他设置, 前端直接看这个Swagg ...

  5. 在Ogre中加载自己的资源包

    转自:http://www.cnblogs.com/minggoddess/archive/2011/02/19/1958472.html 由于数据保护的需要,一款游戏一般都会有自己独有的资源包,这样 ...

  6. 关于请求添加HttpRequestHeader

    WebClient w = new WebClient(); w.Headers.Add(HttpRequestHeader.Accept, "application/json") ...

  7. javascript中对象的属性的特性

    1.ES5的属性特性包括下面六个: configurable: 表示能否通过delete来删除属性从而重新定义属性,能够修改属性的特性,默认为true enumberable: 表示是否能通过for- ...

  8. 《Linux内核设计与实现》读书笔记 - 目录 (完结)【转】

    转自:http://www.cnblogs.com/wang_yb/p/3514730.html 读完这本书回过头才发现, 第一篇笔记居然是 2012年8月发的, 将近一年半的时间才看完这本书(汗!! ...

  9. Entity Framework学习 - 4.Code First升级数据库

    1.在nuget控制台中执行:Enable-Migrations 2.将出现的configuation.cs文件中的AutomaticMigrationsEnabled属性改为true 3.在nuge ...

  10. JFreeChart 图表生成实例(饼图、柱状图、折线图、时序图)

    import java.awt.BasicStroke; import java.awt.Color; import java.io.FileOutputStream; import java.io. ...