Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Jetpack Compose で Adaptive Layout に対応しよう

akkiee76
March 04, 2024

Jetpack Compose で Adaptive Layout に対応しよう

「【ハイブリット開催】Mobile勉強会 Wantedly × チームラボ × Sansan #13」での発表資料です。
https://teamlab.connpass.com/event/310098/

akkiee76

March 04, 2024
Tweet

More Decks by akkiee76

Other Decks in Technology

Transcript

  1. ©2024 RAKUS Co., Ltd. Build Adaptive Layout by Jetpack Compose

    Mobile勉強会 Wantedly × チームラボ × Sansan #13 2024/03/05 @akkiee76
  2. Material3 Foundation 5 Window class (width) Breakpoint (dp) Common devices

    Compact Width < 600 Phone in portrait Medium 600 ≤ width < 840 Tablet in portrait Foldable in portrait (unfolded) Expanded 840 ≤ width < 1200* Phone in landscape Tablet in landscape Foldable in landscape (unfolded) Desktop * Android doesn’t yet support additional window size classes at 1200dp+ https://m3.material.io/foundations/layout/applying-layout/window-size-classes
  3. Material3 Foundation 各 Window Classes で注意すること  1. Compact では小さくて隠れてしまう UI

    の表現  2. スクリーン分割  3. Component の再配置   ・Cards   ・List   ・Feeds   ・Panes 6 https://m3.material.io/foundations/layout/applying-layout/window-size-classes
  4. Adaptive Layout への対応方法 🛠 対応方法は主に以下の 2 パターン  1. Window Size

    Class に応じたレイアウトを設定する  2. Composable 自身をレスポンシブに変更する 8
  5. Window Size Class に応じたレイアウト設定方法 👉 WindowSizeClass が利用可能になる 10 dependencies {

    implementation("androidx.compose.material3:material3-window-size-class:1.2.0") } build.gradle.kts に依存関係を設定すると、
  6. Window Size Class に応じたレイアウト設定方法 11 class MainActivity : AppCompatActivity() {

    @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val windowSizeClass = calculateWindowSizeClass(this) AdaptiveMainScreen(windowSizeClass = windowSizeClass) } } } @Composable fun AdaptiveMainScreen(windowSizeClass: WindowSizeClass) { when (windowSizeClass.widthSizeClass) { WindowWidthSizeClass.Compact -> CompactScreen() WindowWidthSizeClass.Medium -> MediumScreen() WindowWidthSizeClass.Expanded -> ExpandedScreen() } } WindowSizeClassを取得 WindowSizeClassに応じた Composableを定義
  7. Window Size Class に応じたレイアウト設定方法 12 @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) @Composable fun AdaptiveScreen() {

    val activity = LocalContext.current as MainActivity val widthSizeClass = calculateWindowSizeClass(activity = activity).widthSizeClass when (windowSizeClass.widthSizeClass) { WindowWidthSizeClass.Compact -> CompactScreen() WindowWidthSizeClass.Medium -> MediumScreen() WindowWidthSizeClass.Expanded -> ExpandedScreen() } } Composable 内でも使用可能
  8. Composable レスポンシブに変更する方法 14 @Composable fun Card(imageUrl: String, title: String, description:

    String) { BoxWithConstraints { if (maxWidth < 400.dp) { Column { Image(imageUrl) Title(title) } } else { Row { Column { Title(title) Description(description) } Image(imageUrl) } } } } BoxWithConstraints によりレスポンシブにレイアウトに対応可能
  9. Box と BoxWithConstraints の違い 15 @Composable inline fun Box( modifier:

    Modifier = Modifier, contentAlignment: Alignment = Alignment.TopStart, propagateMinConstraints: Boolean = false, content: @Composable BoxScope.() -> Unit ) @Composable fun BoxWithConstraints( modifier: Modifier = Modifier, contentAlignment: Alignment = Alignment.TopStart, propagateMinConstraints: Boolean = false, content: @Composable @UiComposable BoxWithConstraintsScope.() -> Unit )
  10. BoxScope と BoxWithConstraintsScope の違い 16 @LayoutScopeMarker @Immutable interface BoxScope {

    @Stable fun Modifier.align(alignment: Alignment): Modifier @Stable fun Modifier.matchParentSize(): Modifier } @Stable interface BoxWithConstraintsScope : BoxScope { val constraints: Constraints val minWidth: Dp val maxWidth: Dp val minHeight: Dp val maxHeight: Dp }
  11. Adaptive Layout への対応方法を紹介しました。 ・シンプルな UI であるほどレイアウトのスペースに要注意 ⚠ ・すべての Window Class

    Size に対応するのは大変なので、  まずは Expanded とそれ以外から進めると安心 💪 ・BoxWidthConstraints で特定の Compoment に対応するでもOK 💪   まとめ 17