Android View繪制13問13答

rcmsahyj 8年前發布 | 10K 次閱讀 安卓開發 Android開發 移動開發

來自: http://www.cnblogs.com/punkisnotdead/p/5181821.html

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 3 //desire的這2個參數就代表屏幕的寬高, 4 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width); 5 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); 6 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 7 8 9 10 //decorView的measureSpec就是在這里確定的,其實比普通view的measurespec要簡單的多 11 //代碼就不分析了 一目了然的東西 12 private static int getRootMeasureSpec(int windowSize, int rootDimension) { 13 int measureSpec; 14 switch (rootDimension) { 15 16 case ViewGroup.LayoutParams.MATCH_PARENT: 17 // Window can't resize. Force root view to be windowSize. 18 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); 19 break; 20 case ViewGroup.LayoutParams.WRAP_CONTENT: 21 // Window can resize. Set max size for root view. 22 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); 23 break; 24 default: 25 // Window wants to be an exact size. Force root view to be that size. 26 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY); 27 break; 28 } 29 return measureSpec; 30 }

View Code</pre>

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 23 24 25 26 27 //這個算view的spec的方法 看上去一大串 但是真的邏輯非常簡單 就是根據父親viewgroup 28 //的meaurespec 同時還有view自己的params來確定 view自己的measureSpec。 29 //注意這里的參數是padding,這個值的含義是 父容器已占用的控件的大小 所以view的Specsize 30 //的值 你們可以看到 是要減去這個padding的值的。總大小-已經用的 =可用的。 很好理解。 31 32 //然后就是下面的switch邏輯 要自己梳理清楚。其實也不難,主要是下面幾條原則 33 //如果view采用固定寬高,也就是寫死的數值那種。那就不管父親的spec的值了,view的spec 就肯定是exactly 并且大小遵循layout參數里設置的大小。 34 35 //如果view的寬高是match_parent ,那么就要看父容器viewgroup的 spec的值了,如果父view的spec是exactly模式, 36 //那view也肯定是exactly,并且大小就是父容器剩下的空間。如果父容器是at_most模式,那view也是at_most 并且不會超過剩余空間大小 37 38 //如果view的寬高是wrap_content, 那就不管父容器的spec了,view的spec一定是at_most 并且不會超過父view 剩余空間的大小。 39 40 41 public static int getChildMeasureSpec(int spec, int padding, int childDimension) { 42 int specMode = MeasureSpec.getMode(spec); 43 int specSize = MeasureSpec.getSize(spec); 44 45 int size = Math.max(0, specSize - padding); 46 47 int resultSize = 0; 48 int resultMode = 0; 49 50 switch (specMode) { 51 // Parent has imposed an exact size on us 52 case MeasureSpec.EXACTLY: 53 if (childDimension >= 0) { 54 resultSize = childDimension; 55 resultMode = MeasureSpec.EXACTLY; 56 } else if (childDimension == LayoutParams.MATCH_PARENT) { 57 // Child wants to be our size. So be it. 58 resultSize = size; 59 resultMode = MeasureSpec.EXACTLY; 60 } else if (childDimension == LayoutParams.WRAP_CONTENT) { 61 // Child wants to determine its own size. It can't be 62 // bigger than us. 63 resultSize = size; 64 resultMode = MeasureSpec.AT_MOST; 65 } 66 break; 67 68 // Parent has imposed a maximum size on us 69 case MeasureSpec.AT_MOST: 70 if (childDimension >= 0) { 71 // Child wants a specific size... so be it 72 resultSize = childDimension; 73 resultMode = MeasureSpec.EXACTLY; 74 } else if (childDimension == LayoutParams.MATCH_PARENT) { 75 // Child wants to be our size, but our size is not fixed. 76 // Constrain child to not be bigger than us. 77 resultSize = size; 78 resultMode = MeasureSpec.AT_MOST; 79 } else if (childDimension == LayoutParams.WRAP_CONTENT) { 80 // Child wants to determine its own size. It can't be 81 // bigger than us. 82 resultSize = size; 83 resultMode = MeasureSpec.AT_MOST; 84 } 85 break; 86 87 // Parent asked to see how big we want to be 88 case MeasureSpec.UNSPECIFIED: 89 if (childDimension >= 0) { 90 // Child wants a specific size... let him have it 91 resultSize = childDimension; 92 resultMode = MeasureSpec.EXACTLY; 93 } else if (childDimension == LayoutParams.MATCH_PARENT) { 94 // Child wants to be our size... find out how big it should 95 // be 96 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; 97 resultMode = MeasureSpec.UNSPECIFIED; 98 } else if (childDimension == LayoutParams.WRAP_CONTENT) { 99 // Child wants to determine its own size.... find out how 100 // big it should be 101 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; 102 resultMode = MeasureSpec.UNSPECIFIED; 103 } 104 break; 105 } 106 return MeasureSpec.makeMeasureSpec(resultSize, resultMode); 107 }

View Code</pre>

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     }

View Code</pre>

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 
 9 //這個方法特別簡單 基本可以認為就是近似的返回spec中的specSize,除非你的specMode是UNSPECIFIED
10 //UNSPECIFIED 這個一般都是系統內部測量才用的到,這種時候返回size 也就是getSuggestedMinimumWidth的返回值
11  public static int getDefaultSize(int size, int measureSpec) {
12         int result = size;
13         int specMode = MeasureSpec.getMode(measureSpec);
14         int specSize = MeasureSpec.getSize(measureSpec);
15 
16         switch (specMode) {
17         case MeasureSpec.UNSPECIFIED:
18             result = size;
19             break;
20         case MeasureSpec.AT_MOST:
21         case MeasureSpec.EXACTLY:
22             result = specSize;
23             break;
24         }
25         return result;
26 }
27 
28 //跟view的背景相關 這里不多做分析了
29 protected int getSuggestedMinimumWidth() {
30         return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
31     }

View Code</pre>

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     }

View Code</pre>

或者重寫這個方法

  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     }

View Code</pre>

再或者:

  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     }

View Code</pre>

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 Code</pre>

用于設置標志位的 也就是說 如果你的自定義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 
51         int width = getWidth() - paddingLeft - paddingRight;
52         int height = getHeight() - paddingTop - paddingBottom;
53         int radius = Math.min(width, height) / 2;
54         canvas.drawCircle(paddingLeft + width / 2, paddingTop + height / 2, radius, mPaint);
55     }
56 
57     public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
58         super(context, attrs, defStyleAttr);
59         init();
60     }
61 
62     public CircleView(Context context) {
63         super(context);
64         init();
65 
66     }
67 
68     public CircleView(Context context, AttributeSet attrs) {
69         super(context, attrs);
70         init();
71     }
72 }

View Code</pre>

然后下面再給出一個范例,稍微復雜一點是自定義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 
21     public CustomHorizontalLayout(Context context) {
22         super(context);
23     }
24 
25     public CustomHorizontalLayout(Context context, AttributeSet attrs) {
26         super(context, attrs);
27     }
28 
29     public CustomHorizontalLayout(Context context, AttributeSet attrs, int defStyleAttr) {
30         super(context, attrs, defStyleAttr);
31     }
32 
33     @Override
34     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
35         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
36         int measureWidth = 0;
37         int measureHeight = 0;
38         final int childCount = getChildCount();
39         measureChildren(widthMeasureSpec, heightMeasureSpec);
40         int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
41         int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
42         int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
43         int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
44         final View childView = getChildAt(0);
45         final int paddingLeft = getPaddingLeft();
46         final int paddingRight = getPaddingRight();
47         final int paddingTop = getPaddingTop();
48         final int paddingBottom = getPaddingBottom();
49         //沒有子控件 時 我們的寬高要作特殊處理
50         if (childCount == 0) {
51             //當沒有子控件時,如果長寬有一個為wrap 那么就讓這個控件以最小的形式展現
52             //這里我們最小設置為0
53             if (widthSpecMode == MeasureSpec.AT_MOST || heightSpecMode == MeasureSpec.AT_MOST) {
54                 setMeasuredDimension(minWidth, minHeight);
55             } else {
56                 //否則根據我們的layout屬性來
57                 setMeasuredDimension(getLayoutParams().width, getLayoutParams().height);
58             }
59 
60         } else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
61             measureWidth = childView.getMeasuredWidth()  childCount;
62             measureHeight = childView.getMeasuredHeight();
63             setMeasuredDimension(paddingLeft + measureWidth + paddingRight, paddingTop + measureHeight + paddingBottom);
64         } else if (heightSpecMode == MeasureSpec.AT_MOST) {
65             measureHeight = childView.getMeasuredHeight();
66             setMeasuredDimension(paddingLeft + paddingRight + widthSpecSize, paddingTop + paddingBottom + measureHeight);
67         } else if (widthSpecMode == MeasureSpec.AT_MOST) {
68             measureWidth = childView.getMeasuredWidth() * childCount;
69             setMeasuredDimension(paddingLeft + paddingRight + measureWidth, paddingTop + paddingBottom + heightSpecSize);
70         }
71     }
72 
73     @Override
74     protected void onLayout(boolean changed, int l, int t, int r, int b) {
75         final int paddingLeft = getPaddingLeft();
76         final int paddingRight = getPaddingRight();
77         final int paddingTop = getPaddingTop();
78         final int paddingBottom = getPaddingBottom();
79         //左邊初始位置為0
80         int childLeft = 0 + paddingLeft;
81         final int childCount = getChildCount();
82         for (int i = 0; i < childCount; i++) {
83             final View childView = getChildAt(i);
84             if (childView.getVisibility() != View.GONE) {
85                 final int childWidth = childView.getMeasuredWidth();
86                 childView.layout(childLeft, 0 + paddingTop, childLeft + childWidth, paddingTop + childView.getMeasuredHeight());
87                 childLeft += childWidth;
88             }
89         }
90     }
91 }

View Code</pre> </div>

 本文由用戶 rcmsahyj 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!