ViewGroup的官方解析是:

 A <code>ViewGroup</code> is a special view that can contain other views (called children.) The view group is the base class for layouts and views  containers. 

其类定义如下:

public abstract class ViewGroup extends View implements ViewParent, ViewManager

首先是View的子类,并且实现两个接口,这两个接口中分别包含着极为重要的方法,可以说代表着ViewGroup的核心特性。

ViewManager接口定义:

ViewGroup源码部分解析-LMLPHP
 1 package android.view;
2
3 /** Interface to let you add and remove child views to an Activity. To get an instance
4 * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
5 */
6 public interface ViewManager
7 {
8 public void addView(View view, ViewGroup.LayoutParams params);
9 public void updateViewLayout(View view, ViewGroup.LayoutParams params);
10 public void removeView(View view);
11 }
ViewGroup源码部分解析-LMLPHP

ViewParent接口定义:

ViewGroup源码部分解析-LMLPHP
  1 /*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package android.view;
18
19 import android.graphics.Rect;
20
21 /**
22 * Defines the responsibilities for a class that will be a parent of a View.
23 * This is the API that a view sees when it wants to interact with its parent.
24 *
25 */
26 public interface ViewParent {
27 /**
28 * Called when something has changed which has invalidated the layout of a
29 * child of this view parent. This will schedule a layout pass of the view
30 * tree.
31 */
32 public void requestLayout();
33
34 /**
35 * Indicates whether layout was requested on this view parent.
36 *
37 * @return true if layout was requested, false otherwise
38 */
39 public boolean isLayoutRequested();
40
41 /**
42 * Called when a child wants the view hierarchy to gather and report
43 * transparent regions to the window compositor. Views that "punch" holes in
44 * the view hierarchy, such as SurfaceView can use this API to improve
45 * performance of the system. When no such a view is present in the
46 * hierarchy, this optimization in unnecessary and might slightly reduce the
47 * view hierarchy performance.
48 *
49 * @param child the view requesting the transparent region computation
50 *
51 */
52 public void requestTransparentRegion(View child);
53
54 /**
55 * All or part of a child is dirty and needs to be redrawn.
56 *
57 * @param child The child which is dirty
58 * @param r The area within the child that is invalid
59 */
60 public void invalidateChild(View child, Rect r);
61
62 /**
63 * All or part of a child is dirty and needs to be redrawn.
64 *
65 * The location array is an array of two int values which respectively
66 * define the left and the top position of the dirty child.
67 *
68 * This method must return the parent of this ViewParent if the specified
69 * rectangle must be invalidated in the parent. If the specified rectangle
70 * does not require invalidation in the parent or if the parent does not
71 * exist, this method must return null.
72 *
73 * When this method returns a non-null value, the location array must
74 * have been updated with the left and top coordinates of this ViewParent.
75 *
76 * @param location An array of 2 ints containing the left and top
77 * coordinates of the child to invalidate
78 * @param r The area within the child that is invalid
79 *
80 * @return the parent of this ViewParent or null
81 */
82 public ViewParent invalidateChildInParent(int[] location, Rect r);
83
84 /**
85 * Returns the parent if it exists, or null.
86 *
87 * @return a ViewParent or null if this ViewParent does not have a parent
88 */
89 public ViewParent getParent();
90
91 /**
92 * Called when a child of this parent wants focus
93 *
94 * @param child The child of this ViewParent that wants focus. This view
95 * will contain the focused view. It is not necessarily the view that
96 * actually has focus.
97 * @param focused The view that is a descendant of child that actually has
98 * focus
99 */
100 public void requestChildFocus(View child, View focused);
101
102 /**
103 * Tell view hierarchy that the global view attributes need to be
104 * re-evaluated.
105 *
106 * @param child View whose attributes have changed.
107 */
108 public void recomputeViewAttributes(View child);
109
110 /**
111 * Called when a child of this parent is giving up focus
112 *
113 * @param child The view that is giving up focus
114 */
115 public void clearChildFocus(View child);
116
117 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset);
118
119 /**
120 * Find the nearest view in the specified direction that wants to take focus
121 *
122 * @param v The view that currently has focus
123 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
124 */
125 public View focusSearch(View v, int direction);
126
127 /**
128 * Change the z order of the child so it's on top of all other children
129 *
130 * @param child
131 */
132 public void bringChildToFront(View child);
133
134 /**
135 * Tells the parent that a new focusable view has become available. This is
136 * to handle transitions from the case where there are no focusable views to
137 * the case where the first focusable view appears.
138 *
139 * @param v The view that has become newly focusable
140 */
141 public void focusableViewAvailable(View v);
142
143 /**
144 * Bring up a context menu for the specified view or its ancestors.
145 * <p>
146 * In most cases, a subclass does not need to override this. However, if
147 * the subclass is added directly to the window manager (for example,
148 * {@link ViewManager#addView(View, android.view.ViewGroup.LayoutParams)})
149 * then it should override this and show the context menu.
150 *
151 * @param originalView The source view where the context menu was first invoked
152 * @return true if a context menu was displayed
153 */
154 public boolean showContextMenuForChild(View originalView);
155
156 /**
157 * Have the parent populate the specified context menu if it has anything to
158 * add (and then recurse on its parent).
159 *
160 * @param menu The menu to populate
161 */
162 public void createContextMenu(ContextMenu menu);
163
164 /**
165 * This method is called on the parent when a child's drawable state
166 * has changed.
167 *
168 * @param child The child whose drawable state has changed.
169 */
170 public void childDrawableStateChanged(View child);
171
172 /**
173 * Called when a child does not want this parent and its ancestors to
174 * intercept touch events with
175 * {@link ViewGroup#onInterceptTouchEvent(MotionEvent)}.
176 * <p>
177 * This parent should pass this call onto its parents. This parent must obey
178 * this request for the duration of the touch (that is, only clear the flag
179 * after this parent has received an up or a cancel.
180 *
181 * @param disallowIntercept True if the child does not want the parent to
182 * intercept touch events.
183 */
184 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept);
185
186 /**
187 * Called when a child of this group wants a particular rectangle to be
188 * positioned onto the screen. {@link ViewGroup}s overriding this can trust
189 * that:
190 * <ul>
191 * <li>child will be a direct child of this group</li>
192 * <li>rectangle will be in the child's coordinates</li>
193 * </ul>
194 *
195 * <p>{@link ViewGroup}s overriding this should uphold the contract:</p>
196 * <ul>
197 * <li>nothing will change if the rectangle is already visible</li>
198 * <li>the view port will be scrolled only just enough to make the
199 * rectangle visible</li>
200 * <ul>
201 *
202 * @param child The direct child making the request.
203 * @param rectangle The rectangle in the child's coordinates the child
204 * wishes to be on the screen.
205 * @param immediate True to forbid animated or delayed scrolling,
206 * false otherwise
207 * @return Whether the group scrolled to handle the operation
208 */
209 public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
210 boolean immediate);
211 }
ViewGroup源码部分解析-LMLPHP

可以看到addView, removeView, requestLayout, bringChildToFront等等重要的方法都在这两个借口里面得到定义

一、addView方法

所有的addView方法最后都集中到一个方法:

ViewGroup源码部分解析-LMLPHP
 1     /**
2 * Adds a child view with the specified layout parameters.
3 *
4 * @param child the child view to add
5 * @param index the position at which to add the child
6 * @param params the layout parameters to set on the child
7 */
8 public void addView(View child, int index, LayoutParams params) {
9 if (DBG) {
10 System.out.println(this + " addView");
11 }
12
13 // addViewInner() will call child.requestLayout() when setting the new LayoutParams
14 // therefore, we call requestLayout() on ourselves before, so that the child's request
15 // will be blocked at our level
16 requestLayout();
17 invalidate();
18 addViewInner(child, index, params, false);
19 }
ViewGroup源码部分解析-LMLPHP

requestLayout:当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent view重新调用他的onMeasure onLayout来对重新设置自己位置。这里首先安调用自己的requestLayout告诉自己的父View要求重新布局,然后调用invalidate(调用onDraw())要求重绘,然后调用addViewInner去调用child的requestLayout,这个方法的源码如下:

ViewGroup源码部分解析-LMLPHP
 1 private void addViewInner(View child, int index, LayoutParams params,
2 boolean preventRequestLayout) {
3
4 if (child.getParent() != null) {
5 throw new IllegalStateException("The specified child already has a parent. " +
6 "You must call removeView() on the child's parent first.");
7 }
8
9 if (!checkLayoutParams(params)) {
10 params = generateLayoutParams(params);
11 }
12
13 if (preventRequestLayout) {
14 child.mLayoutParams = params;
15 } else {
16 child.setLayoutParams(params);
17 }
18
19 if (index < 0) {
20 index = mChildrenCount;
21 }
22
23 addInArray(child, index);
24
25 // tell our children
26 if (preventRequestLayout) {
27 child.assignParent(this);
28 } else {
29 child.mParent = this;
30 }
31
32 if (child.hasFocus()) {
33 requestChildFocus(child, child.findFocus());
34 }
35
36 AttachInfo ai = mAttachInfo;
37 if (ai != null) {
38 boolean lastKeepOn = ai.mKeepScreenOn;
39 ai.mKeepScreenOn = false;
40 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
41 if (ai.mKeepScreenOn) {
42 needGlobalAttributesUpdate(true);
43 }
44 ai.mKeepScreenOn = lastKeepOn;
45 }
46
47 if (mOnHierarchyChangeListener != null) {
48 mOnHierarchyChangeListener.onChildViewAdded(this, child);
49 }
50
51 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
52 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
53 }
54 }
ViewGroup源码部分解析-LMLPHP

这里可以看到我们写代码的时候经常看到的一个异常,也解释了index的具体含义。我们也可以看到:每一个View都保存了一个指向父View的指针。倒数第二段代码,也用到一个接口,可以监听子View的添加和删除:

ViewGroup源码部分解析-LMLPHP
 1 /**
2 * Interface definition for a callback to be invoked when the hierarchy
3 * within this view changed. The hierarchy changes whenever a child is added
4 * to or removed from this view.
5 */
6 public interface OnHierarchyChangeListener {
7 /**
8 * Called when a new child is added to a parent view.
9 *
10 * @param parent the view in which a child was added
11 * @param child the new child view added in the hierarchy
12 */
13 void onChildViewAdded(View parent, View child);
14
15 /**
16 * Called when a child is removed from a parent view.
17 *
18 * @param parent the view from which the child was removed
19 * @param child the child removed from the hierarchy
20 */
21 void onChildViewRemoved(View parent, View child);
22 }
ViewGroup源码部分解析-LMLPHP

二、removeView

removeView方法除了正常调用requestLayout和invalidate方法以外:

ViewGroup源码部分解析-LMLPHP
 1 /**
2 * Removes the specified range of views from the group.
3 *
4 * @param start the first position in the group of the range of views to remove
5 * @param count the number of views to remove
6 */
7 public void removeViews(int start, int count) {
8 removeViewsInternal(start, count);
9 requestLayout();
10 invalidate();
11 }
ViewGroup源码部分解析-LMLPHP

但是看下面两个方法:

ViewGroup源码部分解析-LMLPHP
 1     /**
2 * {@inheritDoc}
3 */
4 public void removeView(View view) {
5 removeViewInternal(view);
6 requestLayout();
7 invalidate();
8 }
9
10 /**
11 * Removes a view during layout. This is useful if in your onLayout() method,
12 * you need to remove more views.
13 *
14 * @param view the view to remove from the group
15 */
16 public void removeViewInLayout(View view) {
17 removeViewInternal(view);
18 }
ViewGroup源码部分解析-LMLPHP

后者没有调用requestLayout和invalidate,但是后者的说明里面提到是在onLayout()方法中调用这个方法的。所以如果没有猜错的话,在布局完成后调用后面一个方法对界面是没有影响的,好的转入正题:

ViewGroup源码部分解析-LMLPHP
 1 private void removeViewInternal(int index, View view) {
2 boolean clearChildFocus = false;
3 if (view == mFocused) {
4 view.clearFocusForRemoval();
5 clearChildFocus = true;
6 }
7
8 if (view.getAnimation() != null) {
9 addDisappearingView(view);
10 } else if (view.mAttachInfo != null) {
11 view.dispatchDetachedFromWindow();
12 }
13
14 if (mOnHierarchyChangeListener != null) {
15 mOnHierarchyChangeListener.onChildViewRemoved(this, view);
16 }
17
18 needGlobalAttributesUpdate(false);
19
20 removeFromArray(index);
21
22 if (clearChildFocus) {
23 clearChildFocus(view);
24 }
25 }
ViewGroup源码部分解析-LMLPHP

这里的删除貌似只是从Array中删除了一个元素(更加印证了前面提到的说法)。只有调用onLayout和onMeasure方法之后才会诱发界面重新布局。

三、测量函数

ViewGroup源码部分解析-LMLPHP
 1 /**
2 * Ask all of the children of this view to measure themselves, taking into
3 * account both the MeasureSpec requirements for this view and its padding.
4 * We skip children that are in the GONE state The heavy lifting is done in
5 * getChildMeasureSpec.
6 *
7 * @param widthMeasureSpec The width requirements for this view
8 * @param heightMeasureSpec The height requirements for this view
9 */
10 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
11 final int size = mChildrenCount;
12 final View[] children = mChildren;
13 for (int i = 0; i < size; ++i) {
14 final View child = children[i];
15 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
16 measureChild(child, widthMeasureSpec, heightMeasureSpec);
17 }
18 }
19 }
20
21 /**
22 * Ask one of the children of this view to measure itself, taking into
23 * account both the MeasureSpec requirements for this view and its padding.
24 * The heavy lifting is done in getChildMeasureSpec.
25 *
26 * @param child The child to measure
27 * @param parentWidthMeasureSpec The width requirements for this view
28 * @param parentHeightMeasureSpec The height requirements for this view
29 */
30 protected void measureChild(View child, int parentWidthMeasureSpec,
31 int parentHeightMeasureSpec) {
32 final LayoutParams lp = child.getLayoutParams();
33
34 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
35 mPaddingLeft + mPaddingRight, lp.width);
36 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
37 mPaddingTop + mPaddingBottom, lp.height);
38
39 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
40 }
ViewGroup源码部分解析-LMLPHP

前者只不过是告诉这个Group把自己所有的View全部测量一下,后者则是测量单个子View的大小。这边无疑涉及到一个方法:

ViewGroup源码部分解析-LMLPHP
 1 /**
2 * Does the hard part of measureChildren: figuring out the MeasureSpec to
3 * pass to a particular child. This method figures out the right MeasureSpec
4 * for one dimension (height or width) of one child view.
5 *
6 * The goal is to combine information from our MeasureSpec with the
7 * LayoutParams of the child to get the best possible results. For example,
8 * if the this view knows its size (because its MeasureSpec has a mode of
9 * EXACTLY), and the child has indicated in its LayoutParams that it wants
10 * to be the same size as the parent, the parent should ask the child to
11 * layout given an exact size.
12 *
13 * @param spec The requirements for this view
14 * @param padding The padding of this view for the current dimension and
15 * margins, if applicable
16 * @param childDimension How big the child wants to be in the current
17 * dimension
18 * @return a MeasureSpec integer for the child
19 */
20 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
21 int specMode = MeasureSpec.getMode(spec);
22 int specSize = MeasureSpec.getSize(spec);
23
24 int size = Math.max(0, specSize - padding);
25
26 int resultSize = 0;
27 int resultMode = 0;
28
29 switch (specMode) {
30 // Parent has imposed an exact size on us
31 case MeasureSpec.EXACTLY:
32 if (childDimension >= 0) {
33 resultSize = childDimension;
34 resultMode = MeasureSpec.EXACTLY;
35 } else if (childDimension == LayoutParams.MATCH_PARENT) {
36 // Child wants to be our size. So be it.
37 resultSize = size;
38 resultMode = MeasureSpec.EXACTLY;
39 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
40 // Child wants to determine its own size. It can't be
41 // bigger than us.
42 resultSize = size;
43 resultMode = MeasureSpec.AT_MOST;
44 }
45 break;
46
47 // Parent has imposed a maximum size on us
48 case MeasureSpec.AT_MOST:
49 if (childDimension >= 0) {
50 // Child wants a specific size... so be it
51 resultSize = childDimension;
52 resultMode = MeasureSpec.EXACTLY;
53 } else if (childDimension == LayoutParams.MATCH_PARENT) {
54 // Child wants to be our size, but our size is not fixed.
55 // Constrain child to not be bigger than us.
56 resultSize = size;
57 resultMode = MeasureSpec.AT_MOST;
58 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
59 // Child wants to determine its own size. It can't be
60 // bigger than us.
61 resultSize = size;
62 resultMode = MeasureSpec.AT_MOST;
63 }
64 break;
65
66 // Parent asked to see how big we want to be
67 case MeasureSpec.UNSPECIFIED:
68 if (childDimension >= 0) {
69 // Child wants a specific size... let him have it
70 resultSize = childDimension;
71 resultMode = MeasureSpec.EXACTLY;
72 } else if (childDimension == LayoutParams.MATCH_PARENT) {
73 // Child wants to be our size... find out how big it should
74 // be
75 resultSize = 0;
76 resultMode = MeasureSpec.UNSPECIFIED;
77 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
78 // Child wants to determine its own size.... find out how
79 // big it should be
80 resultSize = 0;
81 resultMode = MeasureSpec.UNSPECIFIED;
82 }
83 break;
84 }
85 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
86 }
ViewGroup源码部分解析-LMLPHP

三种模式的判断,进行不同的赋值!这些值会传递给子View,告诉它们父View的大小。

四、布局参数LayoutParams

ViewGroup源码部分解析-LMLPHP
  1 /**
2 * LayoutParams are used by views to tell their parents how they want to be
3 * laid out. See
4 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
5 * for a list of all child view attributes that this class supports.
6 *
7 * <p>
8 * The base LayoutParams class just describes how big the view wants to be
9 * for both width and height. For each dimension, it can specify one of:
10 * <ul>
11 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
12 * means that the view wants to be as big as its parent (minus padding)
13 * <li> WRAP_CONTENT, which means that the view wants to be just big enough
14 * to enclose its content (plus padding)
15 * <li> an exact number
16 * </ul>
17 * There are subclasses of LayoutParams for different subclasses of
18 * ViewGroup. For example, AbsoluteLayout has its own subclass of
19 * LayoutParams which adds an X and Y value.
20 *
21 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
22 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
23 */
24 public static class LayoutParams {
25 /**
26 * Special value for the height or width requested by a View.
27 * FILL_PARENT means that the view wants to be as big as its parent,
28 * minus the parent's padding, if any. This value is deprecated
29 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
30 */
31 @SuppressWarnings({"UnusedDeclaration"})
32 @Deprecated
33 public static final int FILL_PARENT = -1;
34
35 /**
36 * Special value for the height or width requested by a View.
37 * MATCH_PARENT means that the view wants to be as big as its parent,
38 * minus the parent's padding, if any. Introduced in API Level 8.
39 */
40 public static final int MATCH_PARENT = -1;
41
42 /**
43 * Special value for the height or width requested by a View.
44 * WRAP_CONTENT means that the view wants to be just large enough to fit
45 * its own internal content, taking its own padding into account.
46 */
47 public static final int WRAP_CONTENT = -2;
48
49 /**
50 * Information about how wide the view wants to be. Can be one of the
51 * constants FILL_PARENT (replaced by MATCH_PARENT ,
52 * in API Level 8) or WRAP_CONTENT. or an exact size.
53 */
54 @ViewDebug.ExportedProperty(mapping = {
55 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
56 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
57 })
58 public int width;
59
60 /**
61 * Information about how tall the view wants to be. Can be one of the
62 * constants FILL_PARENT (replaced by MATCH_PARENT ,
63 * in API Level 8) or WRAP_CONTENT. or an exact size.
64 */
65 @ViewDebug.ExportedProperty(mapping = {
66 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
67 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
68 })
69 public int height;
70
71 /**
72 * Used to animate layouts.
73 */
74 public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
75
76 /**
77 * Creates a new set of layout parameters. The values are extracted from
78 * the supplied attributes set and context. The XML attributes mapped
79 * to this set of layout parameters are:
80 *
81 * <ul>
82 * <li><code>layout_width</code>: the width, either an exact value,
83 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
84 * {@link #MATCH_PARENT} in API Level 8)</li>
85 * <li><code>layout_height</code>: the height, either an exact value,
86 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
87 * {@link #MATCH_PARENT} in API Level 8)</li>
88 * </ul>
89 *
90 * @param c the application environment
91 * @param attrs the set of attributes from which to extract the layout
92 * parameters' values
93 */
94 public LayoutParams(Context c, AttributeSet attrs) {
95 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
96 setBaseAttributes(a,
97 R.styleable.ViewGroup_Layout_layout_width,
98 R.styleable.ViewGroup_Layout_layout_height);
99 a.recycle();
100 }
101
102 /**
103 * Creates a new set of layout parameters with the specified width
104 * and height.
105 *
106 * @param width the width, either {@link #WRAP_CONTENT},
107 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
108 * API Level 8), or a fixed size in pixels
109 * @param height the height, either {@link #WRAP_CONTENT},
110 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
111 * API Level 8), or a fixed size in pixels
112 */
113 public LayoutParams(int width, int height) {
114 this.width = width;
115 this.height = height;
116 }
117
118 /**
119 * Copy constructor. Clones the width and height values of the source.
120 *
121 * @param source The layout params to copy from.
122 */
123 public LayoutParams(LayoutParams source) {
124 this.width = source.width;
125 this.height = source.height;
126 }
127
128 /**
129 * Used internally by MarginLayoutParams.
130 * @hide
131 */
132 LayoutParams() {
133 }
134
135 /**
136 * Extracts the layout parameters from the supplied attributes.
137 *
138 * @param a the style attributes to extract the parameters from
139 * @param widthAttr the identifier of the width attribute
140 * @param heightAttr the identifier of the height attribute
141 */
142 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
143 width = a.getLayoutDimension(widthAttr, "layout_width");
144 height = a.getLayoutDimension(heightAttr, "layout_height");
145 }
146
147 /**
148 * Returns a String representation of this set of layout parameters.
149 *
150 * @param output the String to prepend to the internal representation
151 * @return a String with the following format: output +
152 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
153 *
154 * @hide
155 */
156 public String debug(String output) {
157 return output + "ViewGroup.LayoutParams={ width="
158 + sizeToString(width) + ", height=" + sizeToString(height) + " }";
159 }
160
161 /**
162 * Converts the specified size to a readable String.
163 *
164 * @param size the size to convert
165 * @return a String instance representing the supplied size
166 *
167 * @hide
168 */
169 protected static String sizeToString(int size) {
170 if (size == WRAP_CONTENT) {
171 return "wrap-content";
172 }
173 if (size == MATCH_PARENT) {
174 return "match-parent";
175 }
176 return String.valueOf(size);
177 }
178 }
ViewGroup源码部分解析-LMLPHP

注解:

1)从API-LEVEL8开始,FILL_PARENT被MATCH_PARENT代替;

2)留下一个疑问:这些布局参数到底是如何变成布局尺寸的?

05-11 22:02