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

はじめてのMaterial3 Expressive

Avatar for yume yume
September 11, 2025

はじめてのMaterial3 Expressive

DroidKaigi 2025 9/11 登壇資料です。

Avatar for yume

yume

September 11, 2025
Tweet

More Decks by yume

Other Decks in Programming

Transcript

  1. 自己紹介 2 chuka / Yume Hakamada X: @YkOxc 24卒でSTORES 株式会社に入社

    STORES 決済 Androidの開発に従事 DroidKaigiスタッフもやってます おいしいちゅうかがたべたい 🦐
  2. @ExperimentalMaterial3ExpressiveApi @Composable fun MaterialTheme( colorScheme: ColorScheme = ... motionScheme: MotionScheme

    = MaterialTheme.motionScheme, shapes: Shapes = ... typography: Typography = ... content: @Composable () -> Unit, ) {...} 19 ・MaterialThemeにMotionSchemeが追加 ・MotionScheme.expressive()またはMotionScheme.standard()を設定 ・デフォルトはStandard ・MaterialExpressiveThemeが追加  → MotionSchemeがデフォルトでExpressive M3 Expressiveのアップデート - Motion -
  3. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 22 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  4. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 23 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders https://developer.android.com/reference/kotlin/androidx/compose/material3 Android DevelopersのMaterial3のページに 各Componentのサンプルコードが掲載されています。 実際に試したい場合はそちらを参照してください◎
  5. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 24 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  6. App bars ・Screen名やナビゲーションを表示 ・画面に関連するアクションを提供 ・Top app barからApp barに名前が変更 ・Search app

    barの追加 ・Subtitleの追加 ・TitleTextAlignの追加 ・MediumとLargeの廃止 ・Medium flexibleとLarge flexibleの追加 https://m3.material.io/components/app-bars/overview 25
  7. App bars - Small app bar - TopAppBar( title =

    { Text("Small app bar") }, subtitle = { Text("Subtitle") }, navigationIcon = {...}, actions = {...}, titleHorizontalAlignment = Alignment.CenterHorizontally, ) TopAppBar( title = { Text("Small app bar") }, subtitle = { Text("Subtitle") }, navigationIcon = {...}, actions = {...}, ) 26
  8. TopAppBar( title = { Text("Small app bar") }, subtitle =

    { Text("Subtitle") }, navigationIcon = {...}, actions = {...}, titleHorizontalAlignment = Alignment.CenterHorizontally, ) TopAppBar( title = { Text("Small app bar") }, subtitle = { Text("Subtitle") }, navigationIcon = {...}, actions = {...}, ) 27 App bars - Small app bar -
  9. App bars - Search app bar- TopAppBar( title = {

    AppBarWithSearch(...) ExpandedFullScreenSearchBar(...) }, subtitle = { }, navigationIcon = {...}, actions = {...}, ) ・Componentはまだ用意されていない ・TopAppBarのtitleにAppBarWithSearchと  ExpandedFullScreenSearchBarを 組み合わせることで実装可能 28
  10. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 29 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  11. 31 val size = ButtonDefaults.MediumContainerHeight Button( onClick = {...}, shapes

    = ButtonDefaults.shapes(), modifier = Modifier.heightIn(size), contentPadding = ButtonDefaults.contentPaddingFor(size), ) { Text("Button", style = ButtonDefaults.textStyleFor(size)) } ToggleButton( checked = checked, onCheckedChange = { checked = it }, modifier = Modifier.heightIn(size), shapes = ToggleButtonDefaults.shapesFor(size), contentPadding = ButtonDefaults.contentPaddingFor(size), ) { Text("ToggleButton", style = ButtonDefaults.textStyleFor(size)) } Common buttons - DefaultとToggle -
  12. 32 val size = ButtonDefaults.MediumContainerHeight Button( onClick = {...}, shapes

    = ButtonDefaults.shapes(), modifier = Modifier.heightIn(size), contentPadding = ButtonDefaults.contentPaddingFor(size), ) { Text("Button", style = ButtonDefaults.textStyleFor(size)) } ToggleButton( checked = checked, onCheckedChange = { checked = it }, modifier = Modifier.heightIn(size), shapes = ToggleButtonDefaults.shapesFor(size), contentPadding = ButtonDefaults.contentPaddingFor(size), ) { Text("ToggleButton", style = ButtonDefaults.textStyleFor(size)) } Common buttons - DefaultとToggle -
  13. 33 val size = ButtonDefaults.MediumContainerHeight Button( onClick = {...}, shapes

    = ButtonDefaults.shapes(), modifier = Modifier.heightIn(size), contentPadding = ButtonDefaults.contentPaddingFor(size), ) { Text("Button", style = ButtonDefaults.textStyleFor(size)) } ToggleButton( checked = checked, onCheckedChange = { checked = it }, modifier = Modifier.heightIn(size), shapes = ToggleButtonDefaults.shapesFor(size), contentPadding = ButtonDefaults.contentPaddingFor(size), ) { Text("ToggleButton", style = ButtonDefaults.textStyleFor(size)) } 押下時の アニメーションを付与 Common buttons - DefaultとToggle -
  14. 34 Button( onClick = {...}, shapes = ButtonDefaults.shapes(), ) {

    Text(...) } Button( onClick = {...}, // 未設定もしくはButtonDefaults.shape shape = ButtonDefaults.shape ) { Text(...) } Button( onClick = {...}, shape = ButtonDefaults.squareShape, ) { Text(...) } Common buttons - RoundとSquare-
  15. 35 Button( onClick = {...}, shapes = ButtonDefaults.shapes(), ) {

    Text(...) } Button( onClick = {...}, // 未設定もしくはButtonDefaults.shape shape = ButtonDefaults.shape ) { Text(...) } Button( onClick = {...}, shape = ButtonDefaults.squareShape, ) { Text(...) } Common buttons - RoundとSquare-
  16. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 36 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  17. Icon buttons - DefaultとToggle - 38 FilledIconButton( onClick = {...},

    shapes = IconButtonDefaults.shapes(), modifier = Modifier.size( IconButtonDefaults.largeContainerSize(), ), ) { Icon( imageVector = Icons.Default.Favorite, contentDescription = null, modifier = Modifier.size(IconButtonDefaults.largeIconSize), ) }
  18. Icon buttons - DefaultとToggle - 39 FilledIconButton( onClick = {...},

    shapes = IconButtonDefaults.shapes(), modifier = Modifier.size( IconButtonDefaults.largeContainerSize(), ), ) { Icon( imageVector = Icons.Default.Favorite, contentDescription = null, modifier = Modifier.size(IconButtonDefaults.largeIconSize), ) }
  19. 40 FilledIconButton( onClick = {...}, shapes = IconButtonDefaults.shapes(), modifier =

    Modifier.size( IconButtonDefaults.largeContainerSize(), ), ) { Icon( imageVector = Icons.Default.Favorite, contentDescription = null, modifier = Modifier.size(IconButtonDefaults.largeIconSize), ) } Icon buttons - DefaultとToggle -
  20. 41 FilledIconToggleButton( checked = checked, onCheckedChange = { checked =

    it }, shapes = IconButtonDefaults.toggleableShapes(), modifier = Modifier.size( IconButtonDefaults.largeContainerSize(), ), ) { Icon( imageVector = Icons.Default.Favorite, contentDescription = null, modifier = Modifier.size(IconButtonDefaults.largeIconSize), ) } Icon buttons - DefaultとToggle -
  21. 42 FilledIconToggleButton( checked = checked, onCheckedChange = { checked =

    it }, shapes = IconButtonDefaults.toggleableShapes(), modifier = Modifier.size( IconButtonDefaults.largeContainerSize(), ), ) { Icon( imageVector = Icons.Default.Favorite, contentDescription = null, modifier = Modifier.size(IconButtonDefaults.largeIconSize), ) } Icon buttons - DefaultとToggle -
  22. 43 FilledIconToggleButton( checked = checked, onCheckedChange = { checked =

    it }, shapes = IconButtonDefaults.toggleableShapes(), modifier = Modifier.size( IconButtonDefaults.largeContainerSize(), ), ) { Icon( imageVector = Icons.Default.Favorite, contentDescription = null, modifier = Modifier.size(IconButtonDefaults.largeIconSize), ) } Icon buttons - DefaultとToggle -
  23. FilledIconButton( onClick = {...}, shapes = IconButtonDefaults.shapes(), ) { Icon(...)

    } FilledIconButton( onClick = {...},   // 未設定もしくはIconButtonDefaults.HogeRoundShape shape = IconButtonDefaults.largeRoundShape, ) { Icon(...) } FilledIconButton( onClick = {...}, shape = IconButtonDefaults.largeSquareShape, ) { Icon(...) } 44 Icon buttons - RoundとSquare -
  24. FilledIconButton( onClick = {...}, shapes = IconButtonDefaults.shapes(), ) { Icon(...)

    } FilledIconButton( onClick = {...},   // 未設定もしくはIconButtonDefaults.HogeRoundShape shape = IconButtonDefaults.largeRoundShape, ) { Icon(...) } FilledIconButton( onClick = {...}, shape = IconButtonDefaults.largeSquareShape, ) { Icon(...) } 45 Icon buttons - RoundとSquare -
  25. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 46 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  26. ButtonGroup( overflowIndicator = { menuState -> FilledIconButton( onClick = {

    if (menuState.isExpanded) { menuState.dismiss() } else { menuState.show() } }, ) { Icon(...) } }, content = { clickableItem(...) toggleableItem(...) customItem(...) }, ) Button groups - Standard - 50
  27. ButtonGroup( overflowIndicator = { menuState -> FilledIconButton( onClick = {

    if (menuState.isExpanded) { menuState.dismiss() } else { menuState.show() } }, ) { Icon(...) } }, content = { clickableItem(...) toggleableItem(...) customItem(...) }, ) overflow時 Button groups - Standard - 51
  28. Button groups - Standard - ButtonGroup( overflowIndicator = { menuState

    -> // overflow時に末尾に表示する Composable }, content = { clickableItem( onClick = {...}, label = "Clickable Item", icon = {...} ) toggleableItem(...) customItem(...) }, ) 52
  29. ButtonGroup( overflowIndicator = { menuState -> // overflow時に末尾に表示する Composable },

    content = { clickableItem(...) toggleableItem( checked = isChecked, onCheckedChange = { isChecked = it }, label = "Toggleable Item", icon = {...} ) customItem(...) }, ) Button groups - Standard - 53
  30. Button groups - Standard - ButtonGroup( overflowIndicator = {...}, content

    = { clickableItem(...) toggleableItem(...) customItem( buttonGroupContent = { OutlinedButton( onClick = {...}, interactionSource = interactionSource, modifier = Modifier .animateWidth(interactionSource1) .defaultMinSize(minWidth = 188.dp), content = {...}, ) }, menuContent = { DropdownMenuItem( text = { Text("Custom Item") }, onClick = {...}, leadingIcon = {...} ) } ) 54
  31. ButtonGroup( overflowIndicator = {...}, content = { clickableItem(...) toggleableItem(...) customItem(

    buttonGroupContent = { OutlinedButton( onClick = {...}, interactionSource = interactionSource, modifier = Modifier .animateWidth(interactionSource1) .defaultMinSize(minWidth = 188.dp), content = {...}, ) }, menuContent = { DropdownMenuItem( text = { Text("Custom Item") }, onClick = {...}, leadingIcon = {...} ) } ) Button groups - Standard - 55
  32. ButtonGroup( overflowIndicator = {...}, content = { clickableItem(...) toggleableItem(...) customItem(

    buttonGroupContent = { OutlinedButton( onClick = {...}, interactionSource = interactionSource, modifier = Modifier .animateWidth(interactionSource1) .defaultMinSize(minWidth = 188.dp), content = {...}, ) }, menuContent = { DropdownMenuItem( text = { Text("Custom Item") }, onClick = {...}, leadingIcon = {...} ) } ) Button groups - Standard - 56 押されたボタンを拡大し、 隣接するボタンを縮小する
  33. ButtonGroup( overflowIndicator = {...}, content = { clickableItem(...) toggleableItem(...) customItem(

    buttonGroupContent = { OutlinedButton( onClick = {...}, interactionSource = interactionSource, modifier = Modifier .animateWidth(interactionSource1) .defaultMinSize(minWidth = 188.dp), content = {...}, ) }, menuContent = { DropdownMenuItem( text = { Text("Custom Item") }, onClick = {...}, leadingIcon = {...} ) } ) Button groups - Standard - 57 minWidthで レイアウト崩れを防ぐ
  34. ButtonGroup( overflowIndicator = {...}, content = { clickableItem(...) toggleableItem(...) customItem(

    buttonGroupContent = { OutlinedButton( onClick = {...}, interactionSource = interactionSource, modifier = Modifier .animateWidth(interactionSource1) .defaultMinSize(minWidth = 188.dp), content = {...}, ) }, menuContent = { DropdownMenuItem( text = { Text("Custom Item") }, onClick = {...}, leadingIcon = {...} ) } ) Button groups - Standard - 58
  35. Button groups - Connected- Row( horizontalArrangement = Arrangement.spacedBy(ButtonGroupDefaults.ConnectedSpaceBetween), ) {

    options.forEachIndexed { index, option -> ToggleButton( checked = selectedIndex == index, onCheckedChange = {...}, shapes = when (index) { 0 -> ButtonGroupDefaults.connectedLeadingButtonShapes() options.lastIndex -> ButtonGroupDefaults.connectedTrailingButtonShapes() else -> ButtonGroupDefaults.connectedMiddleButtonShapes() }, ) { Icon(...) Text(...) } } } 60
  36. Row( horizontalArrangement = Arrangement.spacedBy(ButtonGroupDefaults.ConnectedSpaceBetween), ) { options.forEachIndexed { index, option

    -> ToggleButton( checked = selectedIndex == index, onCheckedChange = {...}, shapes = when (index) { 0 -> ButtonGroupDefaults.connectedLeadingButtonShapes() options.lastIndex -> ButtonGroupDefaults.connectedTrailingButtonShapes() else -> ButtonGroupDefaults.connectedMiddleButtonShapes() }, ) { Icon(...) Text(...) } } } Button groups - Connected- 61 ボタンの位置に応じた押下時の アニメーションを付与
  37. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 62 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  38. Split button ・Material3 Expressiveで追加されたComponent ・メインのアクションと、関連するオプションを表示 ・5つのサイズ  Extra small, Small, Medium,

    Large, Extra large ・4つのスタイル  Elevated, Filled, Tonal, Outlined 63 https://m3.material.io/components/split-button/overview
  39. Split button Box { SplitButtonLayout( leadingButton = { SplitButtonDefaults.LeadingButton(onClick =

    {...}) { Icon( Icons.Filled.Mail, modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize), contentDescription = null, ) Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text("Send Now") } }, trailingButton = {...}, ) DropdownMenu(...) {...} } 64
  40. Split button Box { SplitButtonLayout( leadingButton = { SplitButtonDefaults.LeadingButton(onClick =

    {...}) { Icon( Icons.Filled.Mail, modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize), contentDescription = null, ) Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text("Send Now") } }, trailingButton = {...}, ) DropdownMenu(...) {...} } 65
  41. Split button Box { SplitButtonLayout( leadingButton = {...}, trailingButton =

    { SplitButtonDefaults.TrailingButton( checked = checked, onCheckedChange = { checked = it }, ) { val rotation: Float by animateFloatAsState( targetValue = if (checked) 180f else 0f, label = "trailing rotation", ) Icon( Icons.Filled.KeyboardArrowDown, modifier = Modifier .size(SplitButtonDefaults.TrailingIconSize) .graphicsLayer { this.rotationZ = rotation }, contentDescription = null, ) } }, ) DropdownMenu(...) {...} 66
  42. Split button Box { SplitButtonLayout( leadingButton = {...}, trailingButton =

    { SplitButtonDefaults.TrailingButton( checked = checked, onCheckedChange = { checked = it }, ) { val rotation: Float by animateFloatAsState( targetValue = if (checked) 180f else 0f, label = "trailing rotation", ) Icon( Icons.Filled.KeyboardArrowDown, modifier = Modifier .size(SplitButtonDefaults.TrailingIconSize) .graphicsLayer { this.rotationZ = rotation }, contentDescription = null, ) } }, ) DropdownMenu(...) {...} 67
  43. Split button Box { SplitButtonLayout( leadingButton = {...}, trailingButton =

    { SplitButtonDefaults.TrailingButton( checked = checked, onCheckedChange = { checked = it }, ) { val rotation: Float by animateFloatAsState( targetValue = if (checked) 180f else 0f, label = "trailing rotation", ) Icon( Icons.Filled.KeyboardArrowDown, modifier = Modifier .size(SplitButtonDefaults.TrailingIconSize) .graphicsLayer { this.rotationZ = rotation }, contentDescription = null, ) } }, ) DropdownMenu(expanded = checked, ...) {...} 68
  44. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 69 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  45. FABs -Medium FAB- 71 MediumFloatingActionButton( modifier = Modifier.animateFloatingActionButton( visible =

    isVisible, alignment = Alignment.BottomEnd, ), onClick = {...}, ) { Icon( Icons.Filled.Add, contentDescription = null, modifier = Modifier.size( FloatingActionButtonDefaults.MediumIconSize ), ) }
  46. FABs -Medium FAB- 72 MediumFloatingActionButton( modifier = Modifier.animateFloatingActionButton( visible =

    isVisible, alignment = Alignment.BottomEnd, ), onClick = {...}, ) { Icon( Icons.Filled.Add, contentDescription = null, modifier = Modifier.size( FloatingActionButtonDefaults.MediumIconSize ), ) }
  47. FABs -Medium FAB- 73 MediumFloatingActionButton( modifier = Modifier.animateFloatingActionButton( visible =

    isVisible, alignment = Alignment.BottomEnd, ), onClick = {...}, ) { Icon( Icons.Filled.Add, contentDescription = null, modifier = Modifier.size( FloatingActionButtonDefaults.MediumIconSize ), ) }
  48. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 74 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  49. Extended FAB - Medium extended FAB - MediumExtendedFloatingActionButton( onClick =

    {...}, expanded = isExpanded, icon = { Icon( modifier = Modifier.size( FloatingActionButtonDefaults.MediumIconSize ), ... ) }, text = { Text(text = "Medium Extended FAB") }, ) 76
  50. Extended FAB - Medium extended FAB - MediumExtendedFloatingActionButton( onClick =

    {...}, expanded = isExpanded, icon = { Icon( modifier = Modifier.size( FloatingActionButtonDefaults.MediumIconSize ), ... ) }, text = { Text(text = "Medium Extended FAB") }, ) 77
  51. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 78 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  52. FAB menu FloatingActionButtonMenu( expanded = isExpanded, button = { ToggleFloatingActionButton(

    checked = isExpanded, onCheckedChange = { isExpanded = !isExpanded }, ) { val icon by remember { derivedStateOf { if (checkedProgress > 0.5f) Icons.Filled.Close else Icons.Filled.Add } } Icon( painter = rememberVectorPainter(icon), modifier = Modifier.animateIcon({ checkedProgress }), ) } }, ) { ... } 80
  53. FAB menu FloatingActionButtonMenu( expanded = isExpanded, button = { ToggleFloatingActionButton(

    checked = isExpanded, onCheckedChange = { isExpanded = !isExpanded }, ) { val icon by remember { derivedStateOf { if (checkedProgress > 0.5f) Icons.Filled.Close else Icons.Filled.Add } } Icon( painter = rememberVectorPainter(icon), modifier = Modifier.animateIcon({ checkedProgress }), ) } }, ) { ... } 81
  54. FAB menu FloatingActionButtonMenu(...) { items.forEachIndexed { index, item -> FloatingActionButtonMenuItem(

    onClick = {...}, icon = { Icon(item.icon, contentDescription = null) }, text = { Text(text = item.label) }, ) } } 82
  55. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 83 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  56. Loading indicator // shapeだけのLoadingIndicator LoadingIndicator( polygons = listOf( MaterialShapes.Flower, MaterialShapes.Cookie9Sided,

    MaterialShapes.Triangle ), ) // コンテナ付きのLoadingIndicator ContainedLoadingIndicator( polygons = listOf( MaterialShapes.Flower, MaterialShapes.Cookie9Sided, MaterialShapes.Triangle ), ) 86
  57. Loading indicator -pull to refresh- 87 PullToRefreshBox( isRefreshing = isRefreshing,

    state = state, onRefresh = onRefresh, indicator = { PullToRefreshDefaults.LoadingIndicator( state = state, isRefreshing = isRefreshing, modifier = Modifier.align(Alignment.TopCenter), ) }, ) { ... }
  58. Component紹介 ・App bars ・Common button ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 88 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  59. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 91 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  60. Navigation bar ShortNavigationBar { items.forEachIndexed { index, item -> ShortNavigationBarItem(

    icon = {...}, label = {...}, selected = selectedItem == index, onClick = { selectedItem = index }, ) } } 94
  61. Navigation bar -Horizontal nav item- ShortNavigationBar { items.forEachIndexed { index,

    item -> ShortNavigationBarItem( iconPosition = NavigationItemIconPosition.Start, ... ) } } 95 ・Medium以上の端末で推奨
  62. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 96 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  63. Navigation rail -Collapsed- 98 WideNavigationRail { items.forEachIndexed { index, item

    -> WideNavigationRailItem( icon = { Icon( imageVector = item.icon, contentDescription = null ) }, label = { Text(item.label) }, selected = selectedItem == index, onClick = { selectedItem = index }, ) } }
  64. Navigation rail -Expanded Non-Modal- 100 val state = rememberWideNavigationRailState() WideNavigationRail(

    state = state, header = { IconButton( onClick = { scope.launch { if (state.targetValue == WideNavigationRailValue.Expanded) { state.collapse() } else { state.expand() } } }, ) { if (state.targetValue == WideNavigationRailValue.Expanded) { Icon(Icons.AutoMirrored.Filled.MenuOpen, null) } else { Icon(Icons.Filled.Menu, null) } } }, ) {...}
  65. Navigation rail -Expanded Non-Modal- 101 val state = rememberWideNavigationRailState() WideNavigationRail(

    state = state, header = { IconButton( onClick = { scope.launch { if (state.targetValue == WideNavigationRailValue.Expanded) { state.collapse() } else { state.expand() } } }, ) { if (state.targetValue == WideNavigationRailValue.Expanded) { Icon(Icons.AutoMirrored.Filled.MenuOpen, null) } else { Icon(Icons.Filled.Menu, null) } } }, ) {...}
  66. Navigation rail -Expanded Non-Modal- 102 val state = rememberWideNavigationRailState() WideNavigationRail(

    state = state, header = { IconButton( onClick = { scope.launch { if (state.targetValue == WideNavigationRailValue.Expanded) { state.collapse() } else { state.expand() } } }, ) { if (state.targetValue == WideNavigationRailValue.Expanded) { Icon(Icons.AutoMirrored.Filled.MenuOpen, null) } else { Icon(Icons.Filled.Menu, null) } } }, ) {...}
  67. Navigation rail -Expanded Non-Modal- 103 WideNavigationRail(...) { items.forEachIndexed { index,

    item -> WideNavigationRailItem( railExpanded = state.targetValue == WideNavigationRailValue.Expanded, icon = { Icon( imageVector = item.icon, contentDescription = null ) }, label = { Text(item.label) }, selected = selectedItem == index, onClick = { selectedItem = index }, ) } }
  68. Navigation rail -Expanded Non-Modal- 104 WideNavigationRail(...) { items.forEachIndexed { index,

    item -> WideNavigationRailItem( railExpanded = state.targetValue == WideNavigationRailValue.Expanded, icon = { Icon( imageVector = item.icon, contentDescription = null ) }, label = { Text(item.label) }, selected = selectedItem == index, onClick = { selectedItem = index }, ) } }
  69. Navigation rail -Expanded Modal- 105 val state = rememberWideNavigationRailState() ModalWideNavigationRail(

    state = state, header = { IconButton( onClick = { scope.launch { if (state.targetValue == WideNavigationRailValue.Expanded) { state.collapse() } else { state.expand() } } }, ) { if (state.targetValue == WideNavigationRailValue.Expanded) { Icon(Icons.AutoMirrored.Filled.MenuOpen, null) } else { Icon(Icons.Filled.Menu, null) } } }, ) {...}
  70. Navigation rail -Expanded Modal- 106 val state = rememberWideNavigationRailState() ModalWideNavigationRail(

    state = state, header = { IconButton( onClick = { scope.launch { if (state.targetValue == WideNavigationRailValue.Expanded) { state.collapse() } else { state.expand() } } }, ) { if (state.targetValue == WideNavigationRailValue.Expanded) { Icon(Icons.AutoMirrored.Filled.MenuOpen, null) } else { Icon(Icons.Filled.Menu, null) } } }, ) {...}
  71. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 107 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  72. Toolbars -docked toolbar- FlexibleBottomAppBar( containerColor = MaterialTheme.colorScheme.primaryContainer, ) { items.forEachIndexed

    { index, item -> if (index == 2) { FilledIconButton( modifier = Modifier.size( IconButtonDefaults.smallContainerSize( IconButtonDefaults.IconButtonWidthOption.Wide ) ), onClick = {...}, ) { Icon(item.icon, contentDescription = null) } } else { IconButton(onClick = {...}) { Icon(item.icon, contentDescription = null) } } } } 109
  73. FlexibleBottomAppBar( containerColor = MaterialTheme.colorScheme.primaryContainer, ) { items.forEachIndexed { index, item

    -> if (index == 2) { FilledIconButton( modifier = Modifier.size( IconButtonDefaults.smallContainerSize( IconButtonDefaults.IconButtonWidthOption.Wide ) ), onClick = {...}, ) { Icon(item.icon, contentDescription = null) } } else { IconButton(onClick = {...}) { Icon(item.icon, contentDescription = null) } } } } Toolbars -docked toolbar- 110 Standard Vibrant
  74. FlexibleBottomAppBar( containerColor = MaterialTheme.colorScheme.primaryContainer, ) { items.forEachIndexed { index, item

    -> if (index == 2) { FilledIconButton( modifier = Modifier.size( IconButtonDefaults.smallContainerSize( IconButtonDefaults.IconButtonWidthOption.Wide ) ), onClick = {...}, ) { Icon(item.icon, contentDescription = null) } } else { IconButton(onClick = {...}) { Icon(item.icon, contentDescription = null) } } } } Toolbars -docked toolbar- 111
  75. FlexibleBottomAppBar( containerColor = MaterialTheme.colorScheme.primaryContainer, ) { items.forEachIndexed { index, item

    -> if (index == 2) { FilledIconButton( modifier = Modifier.size( IconButtonDefaults.smallContainerSize( IconButtonDefaults.IconButtonWidthOption.Wide ) ), onClick = {...}, ) { Icon(item.icon, contentDescription = null) } } else { IconButton(onClick = {...}) { Icon(item.icon, contentDescription = null) } } } } Toolbars -docked toolbar- 112
  76. Toolbars -floating toolbar- 113 HorizontalFloatingToolbar( colors = FloatingToolbarDefaults.vibrantFloatingToolbarColors(), leadingContent =

    { IconButton(...) IconButton(...) }, trailingContent = { IconButton(...) IconButton(...) }, content = { FilledIconButton( modifier = Modifier.size( IconButtonDefaults.smallContainerSize( IconButtonDefaults.IconButtonWidthOption.Wide ) ), onClick = {...}, ) { Icon(Icons.Filled.Add, contentDescription = null) } }, )
  77. Toolbars -floating toolbar- 114 HorizontalFloatingToolbar( colors = FloatingToolbarDefaults.vibrantFloatingToolbarColors(), leadingContent =

    { IconButton(...) IconButton(...) }, trailingContent = { IconButton(...) IconButton(...) }, content = { FilledIconButton( modifier = Modifier.size( IconButtonDefaults.smallContainerSize( IconButtonDefaults.IconButtonWidthOption.Wide ) ), onClick = {...}, ) { Icon(Icons.Filled.Add, contentDescription = null) } }, ) Standard Vibrant
  78. Toolbars -floating toolbar- 115 HorizontalFloatingToolbar( colors = FloatingToolbarDefaults.vibrantFloatingToolbarColors(), leadingContent =

    { IconButton(...) IconButton(...) }, trailingContent = { IconButton(...) IconButton(...) }, content = { FilledIconButton( modifier = Modifier.size( IconButtonDefaults.smallContainerSize( IconButtonDefaults.IconButtonWidthOption.Wide ) ), onClick = {...}, ) { Icon(Icons.Filled.Add, contentDescription = null) } }, )
  79. Toolbars -floating toolbar- 116 HorizontalFloatingToolbar( colors = FloatingToolbarDefaults.vibrantFloatingToolbarColors(), leadingContent =

    { IconButton(...) IconButton(...) }, trailingContent = { IconButton(...) IconButton(...) }, content = { FilledIconButton( modifier = Modifier.size( IconButtonDefaults.smallContainerSize( IconButtonDefaults.IconButtonWidthOption.Wide ) ), onClick = {...}, ) { Icon(Icons.Filled.Add, contentDescription = null) } }, )
  80. Toolbars -floating toolbar- 117 HorizontalFloatingToolbar( colors = FloatingToolbarDefaults.vibrantFloatingToolbarColors(), leadingContent =

    { IconButton(...) IconButton(...) }, trailingContent = { IconButton(...) IconButton(...) }, content = { FilledIconButton( modifier = Modifier.size( IconButtonDefaults.smallContainerSize( IconButtonDefaults.IconButtonWidthOption.Wide ) ), onClick = {...}, ) { Icon(Icons.Filled.Add, contentDescription = null) } }, )
  81. Toolbars -floating toolbar- 118 HorizontalFloatingToolbar( colors = FloatingToolbarDefaults.vibrantFloatingToolbarColors(), leadingContent =

    { IconButton(...) IconButton(...) }, trailingContent = { IconButton(...) IconButton(...) }, content = {...}, expanded = isExpanded, )
  82. Toolbars -floating toolbar with FAB- Box( Modifier.floatingToolbarVerticalNestedScroll( expanded = expanded,

    onExpand = { expanded = true }, onCollapse = { expanded = false }, ), ) { HorizontalFloatingToolbar( expanded = expanded, floatingActionButton = { FloatingToolbarDefaults.VibrantFloatingActionButton( onClick = {...}, ) { Icon(Icons.Filled.Add, null) } }, colors = vibrantColors, content = { items.forEachIndexed { index, item -> IconButton(...) }, ) } 119
  83. Toolbars -floating toolbar with FAB- Box( Modifier.floatingToolbarVerticalNestedScroll( expanded = expanded,

    onExpand = { expanded = true }, onCollapse = { expanded = false }, ), ) { HorizontalFloatingToolbar( expanded = expanded, floatingActionButton = { FloatingToolbarDefaults.VibrantFloatingActionButton( onClick = {...}, ) { Icon(Icons.Filled.Add, null) } }, colors = vibrantColors, content = { items.forEachIndexed { index, item -> IconButton(...) }, ) } 120
  84. Toolbars -floating toolbar with FAB- Box( Modifier.floatingToolbarVerticalNestedScroll( expanded = expanded,

    onExpand = { expanded = true }, onCollapse = { expanded = false }, ), ) { HorizontalFloatingToolbar( expanded = expanded, floatingActionButton = { FloatingToolbarDefaults.VibrantFloatingActionButton( onClick = {...}, ) { Icon(Icons.Filled.Add, null) } }, colors = vibrantColors, content = { items.forEachIndexed { index, item -> IconButton(...) }, ) } 121
  85. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 122 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  86. Sliders 125 Slider( state = sliderState, interactionSource = interactionSource, thumb

    = { SliderDefaults.Thumb( sliderState = sliderState, interactionSource = MutableInteractionSource(), thumbSize = DpSize(4.dp, 52.dp), ) }, track = { SliderDefaults.Track( sliderState = sliderState, modifier = Modifier.height(40.dp).drawWithContent { // スタート地点にアイコンを描画する }, trackCornerSize = 12.dp, drawStopIndicator = null, ) }, )
  87. Sliders 126 Slider( state = sliderState, interactionSource = interactionSource, thumb

    = { SliderDefaults.Thumb( sliderState = sliderState, interactionSource = MutableInteractionSource(), thumbSize = DpSize(4.dp, 52.dp), ) }, track = { SliderDefaults.Track( sliderState = sliderState, modifier = Modifier.height(40.dp).drawWithContent { // スタート地点にアイコンを描画する }, trackCornerSize = 12.dp, drawStopIndicator = null, ) }, )
  88. Sliders 127 Slider( state = sliderState, interactionSource = interactionSource, thumb

    = { SliderDefaults.Thumb( sliderState = sliderState, interactionSource = MutableInteractionSource(), thumbSize = DpSize(4.dp, 52.dp), ) }, track = { SliderDefaults.Track( sliderState = sliderState, modifier = Modifier.height(40.dp).drawWithContent { // スタート地点にアイコンを描画する }, trackCornerSize = 12.dp, drawStopIndicator = null, ) }, ) M3 Expressiveで追加された パラメーター trackCornerSizeあり trackCornerSizeなし
  89. Sliders -vertical- 128 val sliderState = rememberSliderState( steps = 3,

    valueRange = -50f..50f, ) VerticalSlider( state = sliderState, interactionSource = interactionSource, reverseDirection = true, )
  90. Component紹介 ・App bars ・Common buttons ・Icon buttons ・Button groups ・Split

    button ・FABs ・Extended FAB ・FAB menu 129 ・Loading indicator ・Progress indicator ・Navigation bar ・Navigation rail ・Toolbars ・Sliders
  91. まとめ 151 ・Material3 Expressive は  「表現力豊かで感情に訴えかけるUX」を実現する新しい選択肢 ・新しい Component / Shape

    / Motion でUI表現の幅が広がる ・プロダクト特性によっては大きなメリットにもリスクにもなる ・4つの観点(特性・ブランド・ユーザビリティ・費用対効果)から  導入を検討することが重要 ・自社プロダクトに最適な形で選択的に導入することが重要