Android Layout Inflater.inflateの使用とソース分析


転載を歓迎します.転載は出所を明記してください.http://blog.csdn.net/johnny901114/article/details/61913656 本論は「余志強のブログ」です.
実際の開発にはしばしばinflateが必要です.レイアウトにその後、あるレイアウト容器に追加します.xmlレイアウトファイルをViewオブジェクトに変換するには、Layout Inflate.inflate方法が必要です.開発にはよく次のような方法があります.
inflater.inflate(layoutId, null);
inflater.inflate(layoutId, root,false);
inflater.inflate(layoutId, root,true);
特に初心者はこのような違いが分かりません.次に彼らの違いを見てみます.
inflanter.inflate(layoutId,null)
今はMainActivityを持っています.このレイアウトにaddのレイアウトを見たいです.このレイアウトは下記の通りです.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:background="#50000000" android:orientation="vertical">

    <Button  android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="inflate01" android:textAllCaps="false" android:textSize="20sp" />

</LinearLayout>
この配置は非常に簡単で、外層はLineear Layoutで、背景色は#50000000で、大きさは全部wrap_contentで、左から20 dpです.
その後MainActivityで追加操作を実行します.
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.inflater01, null);
root.addView(view);
Viewを追加したら、私達が欲しいのではなく、下の図のようになっています.
上の図からわかるように、追加されたViewの幅はwrap_contentではなく、スクリーンいっぱいになっています.leftも効果がありません.つまり私達が設定したこれらは無効になりました.
ソースを見てみます.
inflanter.inflate(R.layout.inflater 01,null)メソッドでinflate(@LayoutRes int resource,@Nullable View Groot,boot atch ToRoot)を呼び出しました.この方法ではinflate(XmlPulser parser)を呼び出しました.
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
    synchronized (mConstructorArgs) {

        final Context inflaterContext = mContext;
        final AttributeSet attrs = Xml.asAttributeSet(parser);
        Context lastContext = (Context) mConstructorArgs[0];
        mConstructorArgs[0] = inflaterContext;
        View result = root;

        try {
            // Look for the root node.
            int type;
            while ((type = parser.next()) != XmlPullParser.START_TAG &&
                    type != XmlPullParser.END_DOCUMENT) {
                // Empty
            }

            final String name = parser.getName();

            if (TAG_MERGE.equals(name)) {
                if (root == null || !attachToRoot) {
                    throw new InflateException("<merge /> can be used only with a valid "
                            + "ViewGroup root and attachToRoot=true");
                }

                rInflate(parser, root, inflaterContext, attrs, false);
            } else {
                // Temp is the root view that was found in the xml
                // xml        View  
                final View temp = createViewFromTag(root, name, inflaterContext, attrs);

                ViewGroup.LayoutParams params = null;

                //    root   
                if (root != null) {
                    // Create layout params that match root, if supplied
                    //   XML      ,  LayoutParamsView LayoutParameter    root  
                    //root           ( LinearLayout)   params         params(LinearLayout.LayoutParams)
                    params = root.generateLayoutParams(attrs);
                    //         ,         params
                    if (!attachToRoot) {
                        // Set the layout params for temp if we are not
                        // attaching. (If we are, we use addView, below)
                        temp.setLayoutParams(params);
                    }
                }

                // Inflate all children under temp against its context.
                //   View      
                rInflateChildren(parser, temp, attrs, true);

                // We are supposed to attach all the views we found (int temp)
                // to root. Do that now.
                if (root != null && attachToRoot) {
                    // View   root   
                    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) {
            //igore code...
        } catch (Exception e) {
            //igore code...
        } finally {
            //igore code...
        }

        return result;
    }
}
上のコードの方が分かりやすいです.主なところにコメントを入れました.
上のコードからinflanter.inflate(layoutId,null)の方法を見て、rootは私達がnullを伝えたため、atach ToRoot=false.
ソースのinflatlate.inflayoutIdによると、nullの方法は次の通りです.
1,xmlの中の関連する属性をViewの対象に変えます.
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
2,最後にView tempを返しました.
だからこのViewにはLayoutParaamsの対象がないのです.
信じないなら、プリントしてもいいです.
View view = inflater.inflate(R.layout.inflater01, null);
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
if (layoutParams == null) {
    Log.e("MainActivity", "layoutParams is null");
} else {
    Log.e("MainActivity", "layoutParams width:height" + layoutParams.width + ":" + layoutParams.height);
}
間違いなくnullを出力します.
一つのViewはLayoutParaamsがないとスクリーンに展示できないです.
今はroot.addViewの方法を見るしかないです.
public void addView(View child) {
    addView(child, -1);
}

public void addView(View child, int index) {
    if (child == null) {
        throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
    }
    LayoutParams params = child.getLayoutParams();
    if (params == null) {
        params = generateDefaultLayoutParams();
        if (params == null) {
            throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
        }
    }
    addView(child, index, params);
}
上から見れば、childのLayoutParaamsがnullであれば、rootはデフォルトのLayoutParaamsを生成します.
だからゲナートDefault LayoutParaamsを見てみます.方法はどうなりますか?私達のこのrootはLineear Layoutなので、Linerer Layoutのgenerate Default LayoutParaamsに行くつもりです.VieGroupではなく、見に行きます.
@Override
protected LayoutParams generateDefaultLayoutParams() {
    if (mOrientation == HORIZONTAL) {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    } else if (mOrientation == VERTICAL) {
        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    }
    return null;
}
私達のrootはLine earLayout方向がVERRTICALなので、LayoutParaams=new LayoutParaams(LayoutParames.MATCHupartENT、LayoutParaams.WRAPuCONTENT)です.これは上の運転の効果を説明しました.設定されている幅と高さはWRAP_です.CONTENTは、最後に幅MATCHになりました.PART、高さはWRAP_CONTENT.
viewGroup.addView(view, LayoutParams); 
          :
view.setLayoutParams(LayoutParams);
viewGroup.addView(view)
ある人は次の三つの属性が失効したと聞きますが、android:background="#50000000"はまた働きますか?
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
ラyoutなのでwidth,layout_height,layout_margin Left,layout_margingLeftは全部LayoutParamesに属していますが、background属性はこの範囲ではなく、同時にすべてのラベル属性はAttributeSetオブジェクトに存在します.
inflanter.inflate(layoutId、root、false);
MainActivityにViewを追加する方法は、以下のようになります.
/** * inflater.inflate(layoutId, root, false); */
private void add02() {
    View view = inflater.inflate(R.layout.inflater01, root, false);
    ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
    if (layoutParams == null) {
        Log.e("MainActivity", "layoutParams is null");
    } else {
        Log.e("MainActivity", "layoutParams width:height" + layoutParams.width + ":" + layoutParams.height);
    }
    root.addView(view);
}
レイアウトファイルですか?それともそのレイアウトファイルですか?違うのはinflate方法のパラメータを指定しただけです.
inflater.inflate(R.layout.inflater01, root, false);
効果は下図の通りです.
これこそ私達が求めている効果です.幅の高さと左側の距離は私達が求めている効果です.
ソースinflater.inflate(R.layout.inflater01, root, false);方法によって実行されるプロセスは以下の通りです.
1,xmlの中の関連する属性をViewの対象に変えます.
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
2,XMLファイルでの設定により、LayoutParames Viewを生成するLayoutParameeterはrootレイアウトに適応し、Viewに設定されている.
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);
}
2,最後にView tempを返しました.
だから、最終的に現れたのは私達の予想に合致したのです.
inflanter.inflate(layoutid、root、true);
inflanter.inflate(layoutid、root、true);とinflater.inflate(layoutId、root、false);唯一の違いはinflater.inflateです.自動的にViewをrootに追加します.私達がaddに入る必要はありません.
/** * inflater.inflate(layoutId, root, true); */
private void add03() {
    View view = inflater.inflate(R.layout.inflater01, root, true);
    ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
    if (layoutParams == null) {
        Log.e("MainActivity", "layoutParams is null");
    } else {
        Log.e("MainActivity", "layoutParams width:height" + layoutParams.width + ":" + layoutParams.height);
    }
}