LayoutInflater(レイアウトサービス)


このセクションの紹介:

このセクションでは引き続き、Android システム サービスの LayoutInflater (レイアウト サービス) を紹介します。 レイアウト XML を作成し、Activity の setContentView() を呼び出してレイアウトをロードし、それを表示することが考えられます。 画面上では、実際、最下層は依然として LayoutInflater であり、Android の組み込みプル パーサーを使用して解析されます。 レイアウト。一般に、Android ではレイアウトを動的に読み込んだり、コントロールを追加したりするためによく使用されます。このセクションでは、実際の開発での使用方法を学びます。 いくつかの使い方~

公式 API ドキュメント:LayoutInflater


1. LayoutInflater の関連紹介


1) Layout とは何ですか?

回答: レイアウトをロードするために使用されるシステム サービスは、レイアウト XML ファイルに対応する View オブジェクトをインスタンス化するために使用されます。これを直接使用することはできません。 現在の Context にバインドされているコンテンツを取得するには、getLayoutInflater() メソッドまたは getSystemService() メソッドを使用する必要があります。 LayoutInflaterインスタンス!


2) LayoutInflaterの使い方

①LayoutInflaterインスタンスを取得する3つの方法:

LayoutInflater inflater1 = LayoutInflater.from(this);  
LayoutInflater inflater2 = getLayoutInflater();  
LayoutInflater inflater3 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);

追記:後の2つは実際に一番下の最初のメソッドを使用します~

②レイアウトメソッドの読み込み:

public View inflate (int リソース、ViewGroup ルート、ブール型attachToRoot) このメソッドの 3 つのパラメータは次のとおりです:

①ロードするレイアウトに対応するリソース ID

②レイアウトの外側に親レイアウトのレイヤーをネストします。そうでない場合は、null を記述するだけです!

③ルート レイアウトを設定するかどうか。このパラメータが設定されていない場合、ロードされたレイアウト ファイルの最外層。 root が null でない場合、デフォルトは true になります root が null の場合、attachToRoot は効果がありません。 root が null でなく、attachToRoot が true の場合、ルート レイアウトはロードされたレイアウト ファイルの最外層にネストされます。 false の場合、root は機能を失います。 簡単に理解すると: 読み込まれたレイアウトにルート外部コンテナを追加するかどうか~!


③LayoutInflater.LayoutParams を通じて関連プロパティを設定する:

たとえば、RelativeLayout は addRule メソッドを通じてルールを追加することもできます。場所を設定するだけです。それは親コンテナを参照していますか? それとも子コントロールを参照しますか?マージンなどを設定するかどうかはあなた次第です~


2. レイアウトをロードする Pure Java コード

私たちは長い間、必要なレイアウトを生成するために XML を使用することに慣れてきましたが、特定のケースでは、 コンポーネントまたはレイアウトをレイアウトに動的に追加するには、Java コードを使用する必要があります。

ただし、Android ページ レイアウトを記述するために完全に Java コードを使用することはお勧めできません。最初のポイントは、コードが大量になるということです。 混乱しやすいため、業務の分離には役立ちません。それでも、レイアウトを完成させるために XML を使用することをお勧めします。 もちろん、Java コードは内部のコンポーネントを変更します。コンポーネントを動的に追加するために Java を使用する必要がある場合もあります。

Pure Java コード読み込みレイアウトプロセス:


——ステップ 1:

コンテナの作成:LinearLayout ly = new LinearLayout(this);

コンポーネントの作成:Button btnOne = new Button(this);

——ステップ 2:

コンテナまたはコンポーネントの関連プロパティを設定できます。 例: LinearLayout、コンポーネントの配置方向を設定できます: ly.setOrientation(LinearLayout.VERTICAL); また、コンポーネントは次のようにすることもできます: たとえば、Button: btnOne.setText("Button 1") ;属性の設定方法については Android API を参照してください。 通常、xml で設定する属性は、setPadding (left、top、right、bottom); のように前に追加するだけです。 3:

コンポーネントまたはコンテナを配置します。この時点で、コンポーネントの追加位置やサイズを設定する必要がある場合があります。 LayoutParams クラスを使用する必要があります。これは、レイアウト コンテナーのカプセル化の位置とサイズの情報パッケージと考えることができます。 情報を待っているクラスです! 最初にサイズを設定する方法を示します: (前の LinearLayout はさまざまなコンテナーに応じて変更できます)

LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(  
        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

は非常に簡単で、次に位置を設定するときに行います。 RelativeLayout のみを考慮してください。 このとき、LayoutParamsのaddRule()メソッドを使用します! addRule()は複数追加することができます! 親コンテナ内のコンポーネントの位置を設定します。

たとえば、

コンポーネントの配置を設定します

:

RelativeLayout rly = new RelativeLayout(this);  
RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
lp2.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);  
Button btnOne = new Button(this);  
rly.addView(btnOne, lp2);
他のコンポーネントの配置を参照してください

: (欠点の 1 つは、参照コンポーネントの ID を手動で設定する必要があることです。これは

manual!!!) 例: btnOne を中央に設定した後、BtnTwo を btnOne の下、親コンテナの右側に配置します。

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        RelativeLayout rly = new RelativeLayout(this);  
        Button btnOne = new Button(this);  
        btnOne.setText("按钮1");  
        Button btnTwo = new Button(this);  
        btnTwo.setText("按钮2");  
        // 为按钮1设置一个id值  
        btnOne.setId(123);  
        // 设置按钮1的位置,在父容器中居中  
        RelativeLayout.LayoutParams rlp1 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
        rlp1.addRule(RelativeLayout.CENTER_IN_PARENT);  
        // 设置按钮2的位置,在按钮1的下方,并且对齐父容器右面  
        RelativeLayout.LayoutParams rlp2 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
        rlp2.addRule(RelativeLayout.BELOW, 123);  
        rlp2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);  
        // 将组件添加到外部容器中  
        rly.addView(btnTwo, rlp2);  
        rly.addView(btnOne, rlp1);  
        // 设置当前视图加载的View即rly  
        setContentView(rly);  
    }  
}
——ステップ 4:

setContentView() メソッドを呼び出してレイアウト オブジェクトをロードします。 さらに、コンテナ内のビューを削除したい場合は、コンテナを呼び出します。removeView

(削除するコンポーネント);

スクリーンショットを実行

:

1.png3. Java コードを動的に追加します。コントロールまたは XML レイアウト


説明した 2 番目のポイントは、純粋な Java コードを使用してレイアウトをロードすることですが、実際にはあまり使用されず、より動的です。 View コントロールを追加し、XML レイアウトを動的に読み込みます。

1) View を動的に追加する Java コード

コンポーネントを動的に追加するには 2 つの方法があります。違いは、最初に setContentView(R.layout.activity_main)

; を行う必要があるかどうかです。 以下は、ボタンを追加するための 2 つの異なる記述方法を示しています:

最初にレイアウト ファイルを記述します: activity_main.xml

:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/RelativeLayout1"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent" >  
  
    <TextView   
        android:id="@+id/txtTitle"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="我是xml文件加载的布局"/>  
</RelativeLayout>
最初のメソッドでは、レイアウト ファイルをロードするために setContentView() を必要としません:

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        Button btnOne = new Button(this);  
        btnOne.setText("我是动态添加的按钮");  
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(    
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
        lp2.addRule(RelativeLayout.CENTER_IN_PARENT);    
        LayoutInflater inflater = LayoutInflater.from(this);  
        RelativeLayout rly = (RelativeLayout) inflater.inflate(  
                R.layout.activity_main, null)  
                .findViewById(R.id.RelativeLayout1);  
        rly.addView(btnOne,lp2);  
        setContentView(rly);  
    }  
}
2 番目のタイプでは、最初にレイアウト ファイルをロードするために setContentView() を必要としません:

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        Button btnOne = new Button(this);  
        btnOne.setText("我是动态添加的按钮");  
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(    
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
        lp2.addRule(RelativeLayout.CENTER_IN_PARENT);    
        RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);  
        rly.addView(btnOne,lp2);  
    }  
}
分析概要

:

コードは非常に簡単です。ボタンを作成した後、ボタンのサイズを設定する LayoutParams オブジェクトを作成しました。 ボタンの位置は、addRule() メソッドを通じて設定されます。

最初の方法: LayoutInflate の inflate() メソッドを通じて activity_main レイアウトをロードし、外側のコンテナを取得します。 次に、addView がコンテナにボタンを追加し、最後に setContentView();

2 番目のメソッド: setContetView() メソッドを通じてレイアウトをロードしているため、この時点で次のメソッドを渡すことができます。 findViewById は外側のコンテナを見つけ、次に addView、最後に setContentView() を実行します!

さらに、setContentView() によって設定されたビュー ノードは XML 全体のルート ノードです!


2) Java コードは XML レイアウトを動的にロードします

次に、今度はxmlファイルを読み込みますxmlファイルを動的に追加します! まず、メイン レイアウト ファイルと動的にロードされるレイアウト ファイルを書き留めます:

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RelativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/btnLoad"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="动态加载布局"/></RelativeLayout>

inflate.xml:

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:gravity="center"  
    android:orientation="vertical"  
    android:id="@+id/ly_inflate" >  
  
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="我是Java代码加载的布局" />  
  
    <Button  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="我是布局里的一个小按钮" />  
  </LinearLayout>

次に、ここで

MainActivity.java XML レイアウトの動的ロードに移動します。 :

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        //获得LayoutInflater对象;  
        final LayoutInflater inflater = LayoutInflater.from(this);    
        //获得外部容器对象  
        final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);  
        Button btnLoad = (Button) findViewById(R.id.btnLoad);  
        btnLoad.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                //加载要添加的布局对象  
                LinearLayout ly = (LinearLayout) inflater.inflate(  
                        R.layout.inflate, null, false).findViewById(  
                        R.id.ly_inflate);  
                //设置加载布局的大小与位置  
                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(    
                        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
                lp.addRule(RelativeLayout.CENTER_IN_PARENT);    
                rly.addView(ly,lp);  
            }  
        });  
    }  
}

実行中のスクリーンショット:

2.gif

コード分析:

①コンテナオブジェクトを取得:

final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);

②Inflaterオブジェクトを取得し、追加したレイアウトのxmlをロードし、最も外側を見つけますfindViewById を介した部分 レイヤーのルート ノード

final LayoutInflater inflater = LayoutInflater.from(this);
LinearLayout ly = (LinearLayout) inflater.inflate(R.layout.inflate, null, false)
   .findViewById(R.id.ly_inflate);

③ このコンテナのサイズと位置情報を設定します:

RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(  
               LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
       lp.addRule(RelativeLayout.CENTER_IN_PARENT);

④ 外側のコンテナに追加します:

rly.addView(ly,lp);


4.LayoutInflater の inflate() メソッドソースコード

最後に、LayoutInflater の inflate() メソッドのソース コードを提供します。興味がある場合は、見てみてください~、実際には単なるプル分析です~

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {    
    synchronized (mConstructorArgs) {    
        final AttributeSet attrs = Xml.asAttributeSet(parser);    
        mConstructorArgs[0] = mContext;    
        View result = root;    
        try {    
            int type;    
            while ((type = parser.next()) != XmlPullParser.START_TAG &&    
                    type != XmlPullParser.END_DOCUMENT) {    
            }    
            if (type != XmlPullParser.START_TAG) {    
                throw new InflateException(parser.getPositionDescription()    
                        + ": No start tag found!");    
            }    
            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, attrs);    
            } else {    
                View temp = createViewFromTag(name, attrs);    
                ViewGroup.LayoutParams params = null;    
                if (root != null) {    
                    params = root.generateLayoutParams(attrs);    
                    if (!attachToRoot) {    
                        temp.setLayoutParams(params);    
                    }    
                }    
                rInflate(parser, temp, attrs);    
                if (root != null && attachToRoot) {    
                    root.addView(temp, params);    
                }    
                if (root == null || !attachToRoot) {    
                    result = temp;    
                }    
            }    
        } catch (XmlPullParserException e) {    
            InflateException ex = new InflateException(e.getMessage());    
            ex.initCause(e);    
            throw ex;    
        } catch (IOException e) {    
            InflateException ex = new InflateException(    
                    parser.getPositionDescription()    
                    + ": " + e.getMessage());    
            ex.initCause(e);    
            throw ex;    
        }    
        return result;    
    }    
}

このセクションの概要:

このセクションでは、Android の LayoutInflater (レイアウト サービス)、およびビューとコントロールの動的読み込みについて説明します。 関連事項、コントロールに慣れていない友達にも役立つと思います~はい、以上です、ありがとう~

3.gif