【Android】ViewGroup源码部分解析(一)

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接口定义:

 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 }

ViewParent接口定义:

  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 }

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

 

一、addView方法

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

 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     }

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

 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     }

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

 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     }

 

二、removeView

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

 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     }

但是看下面两个方法:

 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     }

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

 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     }

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

 

三、测量函数

 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     }

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

 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     }

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

 

四、布局参数LayoutParams

  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     }

注解:

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

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

 

 

 

posted @ 2013-01-24 12:39  大脚印  阅读(2644)  评论(0编辑  收藏  举报