Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る

フレキシブルな UI を作成する

さまざまな画面サイズに対応したアプリを設計する場合、各種のレイアウト構成に合わせてフラグメントを再利用することで、利用可能な画面領域に基づく最適なユーザー エクスペリエンスを提供できるようになります。

たとえば、スマートフォンのように画面が小さく、複数のパネルを表示すると見にくくなる場合は、フラグメントを 1 つのみ表示します。他方、横幅の広いタブレットの場合は、複数のフラグメントを横並びに配置することで、多くの情報をユーザーに表示できます。

図 1: 同じアクティビティであっても画面サイズに応じて異なる構成で表示される 2 つのフラグメント。大きな画面の場合は、両方のフラグメントを横並びにして配置できますが、スマートフォンの場合は 1 つのフラグメントしか表示できないため、ユーザー操作に基づいてフラグメントを置き換える必要があります。

FragmentManager クラスを使用すると、実行時にアクティビティに対してフラグメントの追加、削除、置換ができるようになるため、動的なユーザー エクスペリエンスを実現できます。

フラグメントの実装方法については、以下のリソースをご覧ください。

実行時にフラグメントをアクティビティに追加する

前のレッスンでは、<fragment> 要素を使用して、アクティビティ用のフラグメントをレイアウト ファイル内で定義しましたが、アクティビティの実行時にフラグメントを追加することもできます。アクティビティの実行中にフラグメントを変更する予定の場合は、この方法を使用する必要があります。

フラグメントの追加や削除といったトランザクションを実行するには、FragmentManager を使用して FragmentTransaction を作成する必要があります。これにより、フラグメント トランザクションを追加、削除、置換する API が提供されます。

アクティビティ内のフラグメントの削除や置換を許可する場合は、そのアクティビティの onCreate() メソッドの実行中に、最初のフラグメントをアクティビティに追加するようにしてください。

フラグメントを扱う場合(特に実行時にフラグメントを追加する場合)の重要なルールとして、アクティビティのレイアウト内に、フラグメントを挿入できるコンテナ View を組み込む必要があります。

下記に示すレイアウトは、前のレッスンのレイアウトの代替となるレイアウトで、表示できるフラグメントは一度に 1 つだけになっています。フラグメントを別のフラグメントに置き換えられるように、アクティビティのレイアウト内に、フラグメント コンテナとして機能する空の FrameLayout が組み込まれています。

ファイル名は前のレッスンのレイアウト ファイルと同じですが、今回のレイアウト ディレクトリには large 限定子がありません。したがって、このレイアウトは、デバイスの画面が「大型(large)」よりも小さい場合(両方のフラグメントを同時に表示する領域がない場合)に使用されます。

res/layout/news_articles.xml:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    

アクティビティ内で、サポート ライブラリ API を使用して、getSupportFragmentManager() を呼び出し、FragmentManager を取得します。そして、beginTransaction() を呼び出して FragmentTransaction を作成し、add() を呼び出してフラグメントを追加します。

同じ FragmentTransaction を使用して、アクティビティに対して複数のフラグメント トランザクションを実行できます。変更を加える準備が整ったら、commit() を呼び出す必要があります。

上記のレイアウトにフラグメントを追加する方法を以下に示します。

Kotlin

    import android.os.Bundle
    import android.support.v4.app.FragmentActivity

    class MainActivity : FragmentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.news_articles)

            // Check that the activity is using the layout version with
            // the fragment_container FrameLayout
            if (findViewById(R.id.fragment_container) != null) {

                // However, if we're being restored from a previous state,
                // then we don't need to do anything and should return or else
                // we could end up with overlapping fragments.
                if (savedInstanceState != null) {
                    return;
                }

                // Create a new Fragment to be placed in the activity layout
                val firstFragment = HeadlinesFragment()

                // In case this activity was started with special instructions from an
                // Intent, pass the Intent's extras to the fragment as arguments
                firstFragment.arguments = intent.extras

                // Add the fragment to the 'fragment_container' FrameLayout
                supportFragmentManager.beginTransaction()
                        .add(R.id.fragment_container, firstFragment).commit()
            }
        }
    }
    

Java

    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;

    public class MainActivity extends FragmentActivity {
        @Override
        public void onCreate(Bundle savedInstanceState?) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.news_articles);

            // Check that the activity is using the layout version with
            // the fragment_container FrameLayout
            if (findViewById(R.id.fragment_container) != null) {

                // However, if we're being restored from a previous state,
                // then we don't need to do anything and should return or else
                // we could end up with overlapping fragments.
                if (savedInstanceState != null) {
                    return;
                }

                // Create a new Fragment to be placed in the activity layout
                HeadlinesFragment firstFragment = new HeadlinesFragment();

                // In case this activity was started with special instructions from an
                // Intent, pass the Intent's extras to the fragment as arguments
                firstFragment.setArguments(getIntent().getExtras());

                // Add the fragment to the 'fragment_container' FrameLayout
                getSupportFragmentManager().beginTransaction()
                        .add(R.id.fragment_container, firstFragment).commit();
            }
        }
    }
    

フラグメントは、アクティビティのレイアウト内で <fragment> 要素を使用して定義されているのではなく、実行時に FrameLayout コンテナに追加されています。そのため、アクティビティは、このフラグメントを削除して別のフラグメントに置き換えることができます。

フラグメントを別のフラグメントに置き換える

フラグメントを置換する手順は、フラグメントを追加する手順と似ていますが、add() メソッドの代わりに replace() メソッドを使用します。

置換や削除といったフラグメント トランザクションを行う場合、「戻る」や「元に戻す」などの操作をユーザーが実行できるようにしておくことをおすすめします。フラグメント トランザクション中にユーザーの「戻る」操作を許可するには、FragmentTransaction をコミットする前に addToBackStack() を呼び出す必要があります。

注: フラグメントの削除や置換を行ってトランザクションをバックスタックに追加した場合、削除されたフラグメントは停止します(破棄はされません)。ユーザーが操作を戻してフラグメントを復元すると、再開します。トランザクションをバックスタックに追加しなかった場合は、削除や置換を行ったときにフラグメントは破棄されます。

フラグメントを別のフラグメントに置き換える場合の例を示します。

Kotlin

    // Create fragment and give it an argument specifying the article it should show
    val newFragment = ArticleFragment()
    Bundle args = Bundle()
    args.putInt(ArticleFragment.ARG_POSITION, position)
    newFragment.arguments = args

    val transaction = supportFragmentManager.beginTransaction().apply {
      // Replace whatever is in the fragment_container view with this fragment,
      // and add the transaction to the back stack so the user can navigate back
      replace(R.id.fragment_container, newFragment)
      addToBackStack(null)
    }

    // Commit the transaction
    transaction.commit();
    

Java

    // Create fragment and give it an argument specifying the article it should show
    ArticleFragment newFragment = new ArticleFragment();
    Bundle args = new Bundle();
    args.putInt(ArticleFragment.ARG_POSITION, position);
    newFragment.setArguments(args);

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

    // Replace whatever is in the fragment_container view with this fragment,
    // and add the transaction to the back stack so the user can navigate back
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);

    // Commit the transaction
    transaction.commit();
    

addToBackStack() メソッドは、トランザクションの一意の名前を指定するオプション文字列パラメータを取ります。FragmentManager.BackStackEntry API を使用して高度なフラグメント処理を実行する予定でない場合、この名前は不要です。