ビューを使用したレスポンシブ / アダプティブ デザイン

レスポンシブ/アダプティブ レイアウトを使用すると、画面サイズに関係なく、ユーザー エクスペリエンスが最適化されます。レスポンシブ/アダプティブ レイアウトを実装して、ビューベースのアプリですべてのディスプレイ サイズ、向き、構成(マルチウィンドウ モードなどのサイズ変更可能な構成を含む)をサポートできるようにします。

レスポンシブ デザイン

さまざまなデバイスのフォーム ファクタをサポートするには、まず、アプリで使用できるディスプレイ スペースの量の変化に対応するレイアウトを作成します。

ConstraintLayout

レスポンシブ レイアウトを作成する最善の方法は、UI のベース レイアウトとして ConstraintLayout を使用することです。ConstraintLayout を使用すると、レイアウト内の他のビューとの空間関係に従って、各ビューの位置とサイズを指定できます。表示スペースの変化に応じて、すべてのビューをまとめて移動したり、サイズ変更したりできます。

ConstraintLayout でレイアウトを作成するときは、Android Studio の Layout Editor を使用すると簡単です。Layout Editor を使用すると、XML を手動で編集することなく、新しいビューをレイアウトにドラッグしたり、親ビューと兄弟ビューに対する制約を適用したり、ビュー プロパティを設定したりできます。

図 3. ConstraintLayout を表示している Android Studio の Layout Editor。

詳しくは、ConstraintLayout でレスポンシブ UI を作成するをご覧ください。

レスポンシブな幅と高さ

さまざまなディスプレイ サイズに対してレイアウトをレスポンシブにするには、ビュー コンポーネントの幅と高さに、ハードコードされた値ではなく、wrap_contentmatch_parent、または 0dp (match constraint) を使用します。

  • wrap_content: ビューのサイズを、ビューに含まれるコンテンツに合わせて設定します。
  • match_parent: ビューは親ビュー内で可能な限り拡張されます。
  • 0dp (match constraint): ConstraintLayout 内。match_parent と同様です。ビューは、そのビューの制約内で使用可能なすべてのスペースを占有します。

次に例を示します。

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/lorem_ipsum" />

図 4 は、デバイスの向きに応じてディスプレイの幅が変化したときに TextView の幅と高さがどのように調整されるかを示しています。

図 4. レスポンシブな TextView

TextView は、使用可能なすべてのスペース(match_parent)を満たすように幅を設定し、包含テキストの高さ(wrap_content)に必要なスペースとちょうど同じ高さに設定します。これにより、さまざまなディスプレイ サイズとさまざまなテキスト量にビューを適応させることができます。

LinearLayout を使用している場合は、レイアウト ウェイトに基づいて子ビューを展開し、利用可能なスペースを比例して表示することもできます。ただし、ネストされた LinearLayout で重みを使用するには、各ビューのサイズを決定するために複数のレイアウトパスを実行する必要があり、UI のパフォーマンスが低下します。

ConstraintLayout は、LinearLayout で可能なほぼすべてのレイアウトを、パフォーマンスに影響を与えずに作成できるため、ネストされた LinearLayoutConstraintLayout に変換します。その後、制約チェーンを使用して重み付きレイアウトを定義できます。

アダプティブ デザイン

アプリのレイアウトは、さまざまなディスプレイ サイズに対して常にレスポンシブでなければなりません。ただし、レスポンシブ レイアウトであっても、すべてのデバイスやマルチウィンドウ モードのディスプレイで最適なユーザー エクスペリエンスを提供することはできません。たとえば、スマートフォン用にデザインした UI は、タブレットでは最適なユーザー エクスペリエンスを提供しない可能性があります。アダプティブ デザインは、さまざまなディスプレイ サイズ向けに最適化された代替レイアウトを提供します。

リストと詳細 UI の SlidingPaneLayout

リスト / 詳細 UI は通常、画面サイズに応じて異なるユーザー エクスペリエンスを提供します。大画面では、通常リストペインと詳細ペインは横並びで表示されます。リスト内のアイテムを選択すると、UI を変更せずにアイテム情報が詳細ペインに表示されます。2 つのペインは並んだままになります。ただし、小さい画面では 2 つのペインが別々に表示され、各ペインが表示領域全体を占有します。リストペインのアイテムを選択すると、リストペインが詳細ペイン(選択したアイテムの情報を含む)に置き換えられます。「戻る」ナビゲーションにより、詳細ペインがリストに置き換えられます。

SlidingPaneLayout は、2 つのユーザー エクスペリエンスのどちらが現在のウィンドウ サイズに適しているかを判断するためのロジックを管理します。

<?xml version="1.0" encoding="utf-8"?>
<androidx.slidingpanelayout.widget.SlidingPaneLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="start" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        app:defaultNavHost="true"
        app:navGraph="@navigation/item_navigation" />

</androidx.slidingpanelayout.widget.SlidingPaneLayout>

SlidingPaneLayout に含まれる 2 つのビューの layout_width 属性と layout_weight 属性によって、SlidingPaneLayout の動作が決まります。この例では、ウィンドウが両方のビューを表示できるほど大きい(幅 580 dp 以上)場合、ペインは横並びで表示されます。ただし、ウィンドウの幅が 580 dp より小さい場合、ペインは互いにスライドして、個別にアプリ ウィンドウ全体を占有します。

ウィンドウ幅が指定された最小幅の合計(580 dp)より大きい場合、layout_weight 値を使用して 2 つのペインを比例的にサイズ調整できます。この例では、リストペインには太さがないため、幅は常に 280 dp になります。ただし、詳細ペインは、ビューの layout_weight 設定により、常に 580 dp を超える水平方向のスペースを埋めます。

代替レイアウト リソース

UI デザインをさまざまなディスプレイ サイズに適応させるには、リソース修飾子によって識別される代替レイアウトを使用します。

図 5. 同じアプリが、ディスプレイ サイズごとに異なるレイアウトを使用している。

アプリのソースコード内に追加の res/layout/ ディレクトリを作成することで、画面固有のアダプティブ レイアウトを提供できます。異なるレイアウトを必要とする画面構成ごとにディレクトリを作成します。次に、layout ディレクトリ名に画面構成修飾子を追加します(たとえば、利用可能な幅が 600 dp の画面の場合は layout-w600dp)。

構成修飾子は、アプリの UI に使用可能な表示ディスプレイ領域を表します。アプリのレイアウトを選択する際は、システム デコレーション(ナビゲーション バーなど)とウィンドウ構成の変更(マルチウィンドウ モードなど)が考慮されます。

Android Studio で代替レイアウトを作成する方法については、ビューで UI を作成するレイアウト バリアントを使用して画面ごとに最適化するをご覧ください。

最小幅の修飾子

最小幅の画面サイズ修飾子を使用すると、密度非依存ピクセル(dp)で測定した最小幅のディスプレイに対して代替レイアウトを提供できます。

Android では画面サイズを dp の単位として記述することで、さまざまなピクセル密度を気にすることなく、特定のディスプレイ寸法に合わせたレイアウトを作成できます。

たとえば、スマートフォンやタブレット用に最適化された main_activity という名前のレイアウトを作成するには、さまざまなディレクトリに異なるバージョンのファイルを作成します。

res/layout/main_activity.xml           # For phones (smaller than 600dp smallest width)
res/layout-sw600dp/main_activity.xml   # For 7" tablets (600dp wide or wider)

最小幅の修飾子は、デバイスの現在の向きに関係なく、ディスプレイの両端の最小サイズを指定するため、レイアウトで使用できる全体的なディスプレイ サイズを指定する方法です。

他の最小幅の値と、一般的な画面サイズの対応を次に示します。

  • 320 dp: スマートフォンの小画面(240x320 ldpi、320x480 mdpi、480x800 hdpi など)
  • 480 dp: 5 インチ未満の大画面スマートフォン(480x800 mdpi)
  • 600 dp: 7 インチ タブレット(600x1,024 mdpi)
  • 720 dp: 10 インチ タブレット(720x1280 mdpi、800x1280 mdpi など)

次の図は、画面の dp 幅が画面サイズと画面の向きにどのように対応しているかを示しています。

図 6. さまざまな画面サイズをサポートするための推奨幅ブレークポイント。

最小幅の修飾子の値は dp です。重要なのは、システムが(生のピクセル解像度ではなく)ピクセル密度を認識した後に利用できるディスプレイ領域の大きさだからです。

最小幅などのリソース修飾子を使用して指定するサイズは、実際の画面サイズではありません。サイズは、アプリのウィンドウで使用できる幅または高さを dp 単位で指定します。Android システムでは、システム UI の画面の一部(画面下部のシステムバーや上部のステータスバーなど)に使用されることがあるため、画面の一部がレイアウトで使用できないことがあります。アプリがマルチウィンドウ モードで使用されている場合、アプリはアプリを含むウィンドウのサイズにのみアクセスできます。ウィンドウのサイズを変更すると、新しいウィンドウ サイズで構成の変更がトリガーされ、システムが適切なレイアウト ファイルを選択できるようになります。したがって、宣言するリソース修飾子のサイズでは、アプリに必要なスペースのみを指定する必要があります。レイアウト用のスペースを提供する際に、システム UI で使用されるスペースが考慮されます。

利用可能な幅の修飾子

ディスプレイの最小幅に基づいてレイアウトを変更するのではなく、使用可能な幅または高さに基づいてレイアウトを変更することをおすすめします。たとえば、画面の幅が 600 dp 以上であれば、2 ペイン レイアウトを使用できます。このレイアウトは、デバイスが横向きか縦向きかによって変わります。その場合は、次のように利用可能な幅の修飾子を使用する必要があります。

res/layout/main_activity.xml         # For phones (smaller than 600dp available width)
res/layout-w600dp/main_activity.xml  # For 7" tablets or any screen with 600dp available width
                                     # (possibly landscape phones)

アプリで利用可能な高さが問題になる場合は、利用可能な高さの修飾子を使用できます。たとえば、画面の高さが 600 dp 以上の画面の場合は layout-h600dp です。

向きの修飾子

最小幅と使用可能な幅の修飾子の組み合わせだけで、すべてのサイズ バリエーションをサポートできる場合もありますが、ユーザーが縦向きと横向きを切り替えたときのユーザー エクスペリエンスを変更することをおすすめします。

そのためには、レイアウト ディレクトリ名に port 修飾子または land 修飾子を追加します。向きの修飾子はサイズ修飾子の後に置くようにしてください。次に例を示します。

res/layout/main_activity.xml                # For phones
res/layout-land/main_activity.xml           # For phones in landscape
res/layout-sw600dp/main_activity.xml        # For 7" tablets
res/layout-sw600dp-land/main_activity.xml   # For 7" tablets in landscape

画面構成に関するすべての修飾子について詳しくは、アプリリソースの概要をご覧ください。

ウィンドウ サイズクラス

ウィンドウ サイズクラスは、アダプティブ レイアウトの作成に役立つビューポート ブレークポイントです。ブレークポイントは、アプリで使用できる表示領域を「コンパクト」、「中」、または「拡大」として指定します。幅と高さは個別に指定されるため、アプリは常に、幅用のウィンドウ サイズクラスと、高さ用のウィンドウ サイズクラスを持ちます。

アダプティブ レイアウトをプログラムで適用する手順は次のとおりです。

  • ウィンドウ サイズクラスのブレークポイントに基づいてレイアウト リソースを作成する
  • Jetpack WindowManager ライブラリの WindowSizeClass#compute() 関数を使用して、アプリの幅と高さのウィンドウ サイズクラスを計算します。
  • 現在のウィンドウ サイズクラスのレイアウト リソースをインフレートする

ウィンドウ サイズクラスについて詳しくは、各種の画面サイズのサポートをご覧ください。

フラグメントによる UI コンポーネントのモジュール化

複数のディスプレイ サイズ向けにアプリを設計する場合は、アクティビティ間で UI の動作が不必要に重複しないように、フラグメントを使用して UI ロジックを個別のコンポーネントに抽出します。大画面の場合はフラグメントを組み合わせてマルチペイン レイアウトを作成でき、小画面の場合はフラグメントを別々のアクティビティに配置できます。

たとえば、リストと詳細のパターン(上記の SlidingPaneLayout を参照)は、リストを含むフラグメントとリストアイテムの詳細を含む別のフラグメントで実装できます。大画面ではフラグメントが横並びに表示され、小画面では個別に画面全体に表示されます。

詳しくは、フラグメントの概要をご覧ください。

アクティビティの埋め込み

アプリが複数のアクティビティで構成されている場合は、アクティビティの埋め込みを使用すると、アダプティブ UI を簡単に作成できます。

アクティビティの埋め込みでは、アプリのタスク ウィンドウに複数のアクティビティ、または同じアクティビティの複数のインスタンスを同時に表示します。大画面ではアクティビティを並べて表示できます。小画面では、アクティビティを重ねて表示できます。

アプリのアクティビティの表示方法を決定するには、XML 構成ファイルを作成して、ディスプレイ サイズに基づいて適切なプレゼンテーションを判断します。または、Jetpack WindowManager API 呼び出しを行うこともできます。

アクティビティの埋め込みは、デバイスの向きの変更と折りたたみ式デバイスをサポートし、デバイスの回転、折りたたみ、展開に合わせて、アクティビティの積み重ねと積み重ね解除を行います。

詳しくは、アクティビティの埋め込みをご覧ください。

画面サイズとアスペクト比

さまざまな画面サイズとアスペクト比でアプリをテストして、UI が正しくスケーリングされることを確認します。

Android 10(API レベル 29)以降では、さまざまなアスペクト比がサポートされています。折りたたみ式のフォーム ファクタには、折りたたみ時の 21:9 のような縦長の画面から、広げたときのアスペクト比 1:1 の正方形まで、さまざまなものがあります。

できるだけ多くのデバイスとの互換性を確保するには、次に示すできるだけ多くの画面アスペクト比でアプリをテストします。

図 7. さまざまな画面アスペクト比。

テストするすべての画面サイズのデバイスにアクセスできない場合は、Android Emulator を使用して、ほぼすべての画面サイズをエミュレートできます。

実際のデバイスでテストしたいがデバイスがない場合は、Firebase Test Lab を使用して Google データセンター内のデバイスにアクセスできます。

参考情報