Androidアプリのレイアウトを動的に変化

やりたいこと

Androidアプリの画面(Activity)のレイアウトの一部を実行時に動的に変化させたい

やりかた

Activityのレイアウトで、動的に変化させたい部分のLayout要素に名前(id)を付けておく。ここでは hoge とする。

    <LinearLayout
        android:id="@+id/hoge"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal">
    </LinearLayout>

この部分に動的に挿入する内容のレイアウトを別ファイルで作る。ここでは piyo.xml というファイル名とする。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/piyo"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
    (ここに内容を入れる)
</LinearLayout>

実行時に下記のコードでhogeの部分をpiyo.xmlの内容に変化させる。

    // hogeのLayoutを取得
    LinearLayout layout = (LinearLayout)findViewById(R.id.hoge);
    // hogeの内容を全て消去
    layout.removeAllViews();
    // piyo.xmlの内容を挿入する
    getLayoutInflater().inflate(R.layout.piyo, layout);

注意点

上記のコードのinflateメソッドを実行したすぐ後で、piyo.xmlの内容のViewの高さや幅を取得してもゼロが返ってくることがある。これは、その時点ではまだinflateの処理が完了していないためである。そこで、そのViewないしその親Viewを監視するViewTreeObserverを取得して、レイアウト変化の完了をonGlobalLayoutイベントで知らせてもらう。ただし、このイベントは頻繁に発生する場合があるので、用がすんだらイベントリスナーは削除しておくこと。

// piyoViewというViewを監視するViewTreeObserverを取得
ViewTreeObserver vto = piyoView.getViewTreeObserver();
// レイアウト変化時のイベントリスナを登録
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // ここにレイアウト変化時の処理を記述
        ;
        // 用がすんだらこのイベントリスナを削除
        vto.removeOnGlobalLayoutListener(this);
    }
});