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

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

レスポンシブ デザイン

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

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" />

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

図 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 インチ タブレット(720x1, 280 mdpi、800x1, 280 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 データセンターのデバイスにアクセスできます。

参考情報