在ViewGroup的默認addView 方法中, 若是發現 v 沒有layout參數,則生成一個默認的layoutParams, 這個參數的layout默認是wrap_content的, 因此有時候咱們在xml頂層元素寫的 match_parent不生效, 緣由是 LayoutInflater.inflate(int res, ViewGroup root, boolean attachToRoot) 的第二個參數root咱們設置的是空, 這時候xml頂層元素設置的layout參數將通通忽略, 要想讓這些參數生成v的layoutparams, 須要提供合適的 root, 由於不一樣的ViewGroup子類支持的layout參數是不一樣的。java
/** * Adds a child view. If no layout parameters are already set on the child, the * default parameters for this ViewGroup are set on the child. * * <p><strong>Note:</strong> do not invoke this method from * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)}, * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> * * @param child the child view to add * @param index the position at which to add the child * * @see #generateDefaultLayoutParams() */ public void addView(View child, int index) { LayoutParams params = child.getLayoutParams(); if (params == null) { params = generateDefaultLayoutParams(); if (params == null) { throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); } } addView(child, index, params); } ... /** * Returns a set of default layout parameters. These parameters are requested * when the View passed to {@link #addView(View)} has no layout parameters * already set. If null is returned, an exception is thrown from addView. * * @return a set of default layout parameters or null */ protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); }
好比一個繼承了LinearLayout的MyLinearLayout的初始化init方法中,生成test_layout時傳入的root參數是null, 那麼test_layout生成的view其實並不能填充其parent,只需將null改成this就能夠解決這個問題:node
View v = mLayoutInflater.inflate(R.layout.test_layout, null, false); addView(v);
View v = mLayoutInflater.inflate(R.layout.test_layout, this, false); addView(v);
// test_layot.xml: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:apad="http://schemas.android.com/apk/res/com.taobao.apad" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@color/red"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:layout_marginTop="20dp" .... </LinearLayout>
從下面的inflate過程能夠明顯的看出這一邏輯, 值得一提的是其中對 blink 標籤的處理,會生成一個有閃爍效果的view ==, BlinkLayout 是LayoutInflater的內部類,每一個一個時間(500)會invalidate一次。android
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) { synchronized (mConstructorArgs) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate"); final AttributeSet attrs = Xml.asAttributeSet(parser); Context lastContext = (Context)mConstructorArgs[0]; mConstructorArgs[0] = mContext; View result = root; try { // Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty } if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + ": No start tag found!"); } final String name = parser.getName(); if (TAG_MERGE.equals(name)) { // deal with merge tag } else { // Temp is the root view that was found in the xml View temp; if (TAG_1995.equals(name)) { temp = new BlinkLayout(mContext, attrs); } else { temp = createViewFromTag(root, name, attrs); } ViewGroup.LayoutParams params = null; // if root is not null, the created view will have a non-null layout param if (root != null) { params = root.generateLayoutParams(attrs); if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) temp.setLayoutParams(params); } } if (root != null && attachToRoot) { root.addView(temp, params); } // Decide whether to return the root that was passed in or the // top view found in xml. if (root == null || !attachToRoot) { result = temp; } } } catch (XmlPullParserException e) { ... } finally { // Don't retain static reference on context. mConstructorArgs[0] = lastContext; mConstructorArgs[1] = null; } Trace.traceEnd(Trace.TRACE_TAG_VIEW); return result; } }
像這樣就能夠生成一個閃爍的text view :ide
<blink xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="Blinking text" /> </blink>
另外,在inflate 時若是提供了 containerView, 那麼被inflate的view 會執行一次 onLayout, 若是沒有, 那麼只有等到view被 addView 進一個parentView後才能執行layout。this