さまざまな画面サイズをサポートすることで、さまざまなデバイスと多くのユーザーがアプリにアクセスできます。
できるだけ多くの画面サイズをサポートするには、アプリのレイアウトがレスポンシブ / アダプティブになるように設計する必要があります。レスポンシブ/アダプティブ レイアウトを使用すると、画面サイズに関係なくユーザー エクスペリエンスが最適化されるため、アプリはスマートフォン、タブレット、折りたたみ式デバイス、ChromeOS デバイス、縦向きと横向き、サイズ変更可能な設定(マルチ ウィンドウ モードなど)に対応できます。
ウィンドウ サイズクラス
ウィンドウ サイズクラスは、レスポンシブ/アダプティブ レイアウトの設計、開発、テストに役立つ独自のビューポート ブレークポイントのセットです。ブレークポイントは、レイアウトのシンプルさと、固有のケースに合わせてアプリを最適化できる柔軟性のバランスを取ります。
ウィンドウ サイズクラスは、アプリで利用可能な表示領域をコンパクト、中程度、拡大に分類します。利用可能な幅と高さは個別に分類されるため、どの時点でも、アプリにはウィンドウ サイズクラスが 2 つ(幅用と高さ用)あります。縦方向のスクロールが多いため、通常、利用可能な幅は利用可能な高さよりも重要です。そのため、幅のウィンドウ サイズクラスはアプリの UI により適切であると考えられます。
図に示すように、ブレークポイントを使用すると、デバイスと構成の観点からレイアウトについて引き続き検討できます。各サイズクラスのブレークポイントは、典型的なデバイス シナリオの一般的なケースを表しており、ブレークポイントに基づくレイアウトの設計を検討する際の基準として有用です。
サイズクラス | ブレークポイント | デバイスによる表現 |
---|---|---|
コンパクトな幅 | 幅 600 dp 未満 | 縦向きのスマートフォンの 99.96% |
中程度の幅 | 幅 600 dp 以上 840 dp 未満 | 縦向きのタブレットの 93.73% 広げた状態の最も大きなインナー ディスプレイ(縦向き) |
拡大幅 | 幅 840 dp 以上 | 横向きのタブレットの 97.22% 展開した状態の最も大きなインナー ディスプレイ(横向き) |
コンパクトな高さ | 高さ 480 dp 未満 | 横向きのスマートフォンの 99.78% |
中程度の高さ | 高さ 480 dp 以上 900 dp 未満 | 横向きのタブレットの 96.56% 縦向きのスマートフォンの 97.59% |
拡大高さ | 高さ 900 dp 以上 | 縦向きのタブレットの 94.25% |
サイズクラスを物理デバイスとして可視化すると便利ですが、ウィンドウ サイズクラスはデバイス画面のサイズによって明示的に決まるわけではありません。ウィンドウ サイズクラスは isTablet タイプのロジック用ではありません。ウィンドウ サイズクラスは、アプリが実行されているデバイスのタイプに関係なく、アプリで使用できるウィンドウ サイズによって決まります。これには 2 つの重要な影響があります。
物理デバイスで、特定のウィンドウ サイズクラスが保証されるわけではありません。アプリで利用可能な画面スペースは、さまざまな理由により、デバイスの画面サイズと異なります。モバイル デバイスでは、分割画面モードによって 2 つのアプリ間で画面を分割できます。ChromeOS では、任意にサイズ変更可能なフリーフォーム ウィンドウで Android アプリを表示できます。折りたたみ式デバイスでは、デバイスを折りたたむか広げることで、2 種類の画面サイズを個別に利用できます。
ウィンドウ サイズクラスは、アプリの全期間を通じて変わる可能性があります。アプリの実行中に、デバイスの向きの変更、マルチタスク、折りたたみ、展開により、利用可能な画面スペースが変化することがあります。そのため、ウィンドウ サイズクラスは動的であり、アプリの UI はそれに合わせて調整する必要があります。
ウィンドウ サイズクラスは、マテリアル デザインのレスポンシブ レイアウト グリッドのレイアウト ブレークポイントに対応します。ウィンドウ サイズクラスを使用すると、追加の画面スペースを活用するために特定の正規レイアウトを使用するかどうかの判断など、アプリのレイアウトに関する高度な決定を行うことができます。
現在の WindowSizeClass
は、Jetpack WindowManager ライブラリに用意されている WindowSizeClass#compute()
関数を使用して計算できます。次の例は、ウィンドウ サイズクラスを計算し、ウィンドウ サイズクラスが変更されるたびに更新を受け取る方法を示しています。
Kotlin
class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. val container: ViewGroup = binding.container // Add a utility view to the container to hook into // View.onConfigurationChanged(). This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged(), // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged() is // called in those scenarios. container.addView(object : View(this) { override fun onConfigurationChanged(newConfig: Configuration?) { super.onConfigurationChanged(newConfig) computeWindowSizeClasses() } }) computeWindowSizeClasses() } private fun computeWindowSizeClasses() { val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this) val width = metrics.bounds.width() val height = metrics.bounds.height() val density = resources.displayMetrics.density val windowSizeClass = WindowSizeClass.compute(width/density, height/density) // COMPACT, MEDIUM, or EXPANDED val widthWindowSizeClass = windowSizeClass.windowWidthSizeClass // COMPACT, MEDIUM, or EXPANDED val heightWindowSizeClass = windowSizeClass.windowHeightSizeClass // Use widthWindowSizeClass and heightWindowSizeClass. } }
Java
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. ViewGroup container = binding.container; // Add a utility view to the container to hook into // View.onConfigurationChanged(). This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged(), // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged() is // called in those scenarios. container.addView(new View(this) { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); computeWindowSizeClasses(); } }); computeWindowSizeClasses(); } private void computeWindowSizeClasses() { WindowMetrics metrics = WindowMetricsCalculator.getOrCreate() .computeCurrentWindowMetrics(this); int width = metrics.getBounds().width int height = metrics.getBounds().height() float density = getResources().getDisplayMetrics().density; WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density) // COMPACT, MEDIUM, or EXPANDED WindowWidthSizeClass widthWindowSizeClass = windowSizeClass.getWindowWidthSizeClass() // COMPACT, MEDIUM, or EXPANDED WindowHeightSizeClass heightWindowSizeClass = windowSizeClass.getWindowHeightSizeClass() // Use widthWindowSizeClass and heightWindowSizeClass. } }
アプリでウィンドウ サイズクラスを確認したら、現在のウィンドウ サイズクラスに基づいてレイアウトの変更を開始できます。
レイアウトとウィンドウ サイズクラス
レイアウトを変更する際は、すべてのウィンドウ サイズ(特にコンパクト、中程度、拡大のブレークポイント幅)でレイアウトの動作をテストします。
コンパクト画面用の既存のレイアウトがある場合は、まず拡大幅サイズクラスに合わせてレイアウトを最適化します。これは、このサイズクラスが追加のコンテンツや UI の変更を行うためのスペースが最大であるためです。次に、中程度の幅のサイズクラスに適したレイアウトを決定します。専用のレイアウトの追加を検討してください。
次のステップ
ウィンドウ サイズクラスを使用してレスポンシブ/アダプティブ レイアウトを作成する方法について詳しくは、以下をご覧ください。
Compose ベースのレイアウトの場合: アダプティブ レイアウトを作成する
ビューベースのレイアウトの場合: ビューを使用したレスポンシブ/アダプティブ デザイン
すべてのデバイスと画面サイズで優れたアプリを実現する方法について詳しくは、以下をご覧ください。