Jetpack Compose には、デジタル インターフェースを作成するための包括的なデザイン システムであるマテリアル デザインの実装が用意されています。マテリアル コンポーネント(ボタン、カード、スイッチなど)と Scaffold
などのレイアウトは、コンポーズ可能な関数として使用できます。
マテリアル コンポーネントは、ユーザー インターフェースを作成するためのインタラクティブなビルディング ブロックです。Compose には、こうしたコンポーネントが複数用意されており、すぐに使用できます。利用可能なコンポーネントについては、Compose Material API リファレンスをご覧ください。
マテリアル コンポーネントは、アプリで MaterialTheme
が提供する値を使用します。
@Composable
fun MyApp() {
MaterialTheme {
// Material Components like Button, Card, Switch, etc.
}
}
テーマ設定について詳しくは、Compose のデザイン システムに関するガイドをご覧ください。
コンテンツ スロット
内側のコンテンツ(テキストラベル、アイコンなど)をサポートするマテリアル コンポーネントは、マテリアルの仕様に合わせて内側のコンテンツのレイアウトをサポートするために、パブリック定数(サイズやパディングなど)だけでなく「スロット」(コンポーズ可能なコンテンツを受け入れる汎用ラムダ)も提供する傾向にあります。
Button
がその一例です。
Button(
onClick = { /* ... */ },
// Uses ButtonDefaults.ContentPadding by default
contentPadding = PaddingValues(
start = 20.dp,
top = 12.dp,
end = 20.dp,
bottom = 12.dp
)
) {
// Inner content including an icon and a text label
Icon(
Icons.Filled.Favorite,
contentDescription = "Favorite",
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text("Like")
}
図 1. content
スロットとデフォルトのパディングを使用する Button
(左)と、カスタム contentPadding
を提供する content
スロットを使用する Button
(右)。
Button
には汎用の content
後置ラムダスロットがあり、RowScope
を使用してコンテンツのコンポーザブルを一列にレイアウトします。また、内側のコンテンツにパディングを適用するための contentPadding
パラメータもあります。ButtonDefaults
で提供される定数またはカスタム値を使用できます。
別の例として、ExtendedFloatingActionButton
が挙げられます。
ExtendedFloatingActionButton(
onClick = { /* ... */ },
icon = {
Icon(
Icons.Filled.Favorite,
contentDescription = "Favorite"
)
},
text = { Text("Like") }
)
図 2. icon
スロットと text
スロットを使用する ExtendedFloatingActionButton
。
ExtendedFloatingActionButton
には、汎用の content
ラムダの代わりに、icon
と text
ラベル用のスロットが 2 つあります。各スロットは汎用のコンポーズ可能なコンテンツをサポートしていますが、コンポーネントはこうした内側のコンテンツのレイアウト方法を決定します。パディング、アライメント、サイズは内部で処理されます。
Scaffold
Compose には、マテリアル コンポーネントを一般的な画面パターンに組み合わせるための便利なレイアウトが用意されています。Scaffold
などのコンポーザブルは、さまざまなコンポーネントやその他の画面要素用のスロットを提供します。
画面のコンテンツ
Scaffold
には汎用の content
後置ラムダスロットがあります。このラムダは、トップバーとボトムバーがある場合、それをオフセットするために(たとえば Modifier.padding
を介して)コンテンツ ルートに適用される PaddingValues
のインスタンスを受け取ります。
Scaffold(/* ... */) { contentPadding ->
// Screen content
Box(modifier = Modifier.padding(contentPadding)) { /* ... */ }
}
アプリバー
Scaffold
は、トップ アプリバーまたはボトム アプリバー用のスロットを提供します。コンポーザブルの配置は内部で処理されます。
topBar
スロットと TopAppBar
を使用できます。
Scaffold(
topBar = {
TopAppBar { /* Top app bar content */ }
}
) {
// Screen content
}
bottomBar
スロットと BottomAppBar
を使用できます。
Scaffold(
bottomBar = {
BottomAppBar { /* Bottom app bar content */ }
}
) {
// Screen content
}
これらのスロットは、BottomNavigation
などの他のマテリアル コンポーネントに使用できます。カスタム コンポーザブルも使用できます。たとえば Owl サンプルのオンボーディング画面をご覧ください。
フローティング操作ボタン
Scaffold
はフローティング操作ボタン用のスロットを提供します。
floatingActionButton
スロットと FloatingActionButton
を使用できます。
Scaffold(
floatingActionButton = {
FloatingActionButton(onClick = { /* ... */ }) {
/* FAB content */
}
}
) {
// Screen content
}
FAB コンポーザブルの下部配置は内部で処理されます。floatingActionButtonPosition
パラメータを使用すると水平方向の位置を調整できます。
Scaffold(
floatingActionButton = {
FloatingActionButton(onClick = { /* ... */ }) {
/* FAB content */
}
},
// Defaults to FabPosition.End
floatingActionButtonPosition = FabPosition.Center
) {
// Screen content
}
Scaffold
コンポーザブルの bottomBar
スロットを使用している場合は、isFloatingActionButtonDocked
パラメータを使用すると FAB をボトム アプリバーと重ねることができます。
Scaffold(
floatingActionButton = {
FloatingActionButton(onClick = { /* ... */ }) {
/* FAB content */
}
},
// Defaults to false
isFloatingActionButtonDocked = true,
bottomBar = {
BottomAppBar { /* Bottom app bar content */ }
}
) {
// Screen content
}
図 3. floatingActionButton
スロットと bottomBar
スロットを使用する Scaffold
。isFloatingActionButtonDocked
パラメータを false
(上部)と true
(下部)に設定しています。
BottomAppBar
は、任意の Shape
を受け入れる cutoutShape
パラメータで FAB カットアウトをサポートしています。ドッキングしたコンポーネントで使用されているものと同じ Shape
を指定することをおすすめします。たとえば次の FloatingActionButton
は、shape
パラメータのデフォルト値として、コーナーサイズ 50% の MaterialTheme.shapes.small
を使用しています。
Scaffold(
floatingActionButton = {
FloatingActionButton(onClick = { /* ... */ }) {
/* FAB content */
}
},
isFloatingActionButtonDocked = true,
bottomBar = {
BottomAppBar(
// Defaults to null, that is, No cutout
cutoutShape = MaterialTheme.shapes.small.copy(
CornerSize(percent = 50)
)
) {
/* Bottom app bar content */
}
}
) {
// Screen content
}
図 4. BottomAppBar
とドッキングした FloatingActionButton
を持つ Scaffold
。BottomAppBar
には、FloatingActionButton
で使用されている Shape
と一致するカスタム cutoutShape
があります。
スナックバー
Scaffold
はスナックバーを表示する手段を提供します。
これは、SnackbarHostState
プロパティを含む ScaffoldState
を介して提供されます。rememberScaffoldState
を使用して、scaffoldState
パラメータで Scaffold
に渡す必要のある ScaffoldState
のインスタンスを作成できます。SnackbarHostState
は、showSnackbar
関数へのアクセスを提供します。この suspend 関数は CoroutineScope
を必要とし(たとえば rememberCoroutineScope
を使用)、UI イベントに応じて呼び出され、Scaffold
内に Snackbar
を表示します。
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
floatingActionButton = {
ExtendedFloatingActionButton(
text = { Text("Show snackbar") },
onClick = {
scope.launch {
scaffoldState.snackbarHostState
.showSnackbar("Snackbar")
}
}
)
}
) {
// Screen content
}
任意のアクションを指定し、Snackbar
の継続時間を調整できます。snackbarHostState.showSnackbar
関数は追加の actionLabel
パラメータと duration
パラメータを受け入れ、SnackbarResult
を返します。
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
floatingActionButton = {
ExtendedFloatingActionButton(
text = { Text("Show snackbar") },
onClick = {
scope.launch {
val result = scaffoldState.snackbarHostState
.showSnackbar(
message = "Snackbar",
actionLabel = "Action",
// Defaults to SnackbarDuration.Short
duration = SnackbarDuration.Indefinite
)
when (result) {
SnackbarResult.ActionPerformed -> {
/* Handle snackbar action performed */
}
SnackbarResult.Dismissed -> {
/* Handle snackbar dismissed */
}
}
}
}
)
}
) {
// Screen content
}
snackbarHost
パラメータでカスタムの Snackbar
を指定できます。詳しくは SnackbarHost API reference docs
をご覧ください。
ドロワー
Scaffold
はモーダル ナビゲーション ドロワー用のスロットを提供します。ドラッグ可能なシートとコンポーザブルのレイアウトは内部で処理されます。
drawerContent
スロットでは、ColumnScope
を使用してドロワー コンテンツのコンポーザブルを一列にレイアウトできます。
Scaffold(
drawerContent = {
Text("Drawer title", modifier = Modifier.padding(16.dp))
Divider()
// Drawer items
}
) {
// Screen content
}
Scaffold
は他にさまざまなドロワー パラメータを受け入れます。たとえば drawerGesturesEnabled
パラメータで、ドロワーがドラッグに応答するかどうかを切り替えることができます。
Scaffold(
drawerContent = {
// Drawer content
},
// Defaults to true
drawerGesturesEnabled = false
) {
// Screen content
}
プログラムによるドロワーの開閉は ScaffoldState
を介して行います。これには scaffoldState
パラメータを使用して Scaffold
に渡す必要のある DrawerState
プロパティが含まれています。DrawerState
は、現在のドロワーの状態に関連するプロパティだけでなく、open
関数と close
関数へのアクセスを提供します。これらの suspend 関数は CoroutineScope
を必要とし(たとえば rememberCoroutineScope
を使用)、UI イベントに応じて呼び出すことができます。
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
drawerContent = {
// Drawer content
},
floatingActionButton = {
ExtendedFloatingActionButton(
text = { Text("Open or close drawer") },
onClick = {
scope.launch {
scaffoldState.drawerState.apply {
if (isClosed) open() else close()
}
}
}
)
}
) {
// Screen content
}
モーダル ドロワー
Scaffold
を使用せずにモーダル ナビゲーション ドロワーを実装する場合は、ModalDrawer
コンポーザブルを使用できます。Scaffold
と同様のドロワー パラメータを使用できます。
val drawerState = rememberDrawerState(DrawerValue.Closed)
ModalDrawer(
drawerState = drawerState,
drawerContent = {
// Drawer content
}
) {
// Screen content
}
ボトム ナビゲーション ドロワーを実装する場合は BottomDrawer
コンポーザブルを使用できます。
val drawerState = rememberBottomDrawerState(BottomDrawerValue.Closed)
BottomDrawer(
drawerState = drawerState,
drawerContent = {
// Drawer content
}
) {
// Screen content
}
ボトムシート
標準のボトムシートを実装する場合は BottomSheetScaffold
コンポーザブルを使用できます。topBar
、floatingActionButton
、snackbarHost
など、Scaffold
と同様のパラメータを使用できます。これには、ボトムシートを表示する手段を提供する追加のパラメータが含まれています。
sheetContent
スロットでは、ColumnScope
を使用してシート コンテンツのコンポーザブルを一列にレイアウトできます。
BottomSheetScaffold(
sheetContent = {
// Sheet content
}
) {
// Screen content
}
BottomSheetScaffold
は他にさまざまなシート パラメータを受け入れます。たとえば、sheetPeekHeight
パラメータでシートのピーク高さを設定できます。sheetGesturesEnabled
パラメータで、ドロワーがドラッグに応答するかどうかを切り替えることもできます。
BottomSheetScaffold(
sheetContent = {
// Sheet content
},
// Defaults to BottomSheetScaffoldDefaults.SheetPeekHeight
sheetPeekHeight = 128.dp,
// Defaults to true
sheetGesturesEnabled = false
) {
// Screen content
}
プログラムによるシートの開閉は BottomSheetScaffoldState
を介して行います。これには BottomSheetState
プロパティが含まれています。rememberBottomSheetScaffoldState
を使用して、scaffoldState
パラメータで BottomSheetScaffold
に渡す必要のある BottomSheetScaffoldState
のインスタンスを作成できます。BottomSheetState
は、現在のシートの状態に関連するプロパティだけでなく、expand
関数と collapse
関数へのアクセスを提供します。これらの suspend 関数は CoroutineScope
を必要とし(たとえば rememberCoroutineScope
を使用)、UI イベントに応じて呼び出すことができます。
val scaffoldState = rememberBottomSheetScaffoldState()
val scope = rememberCoroutineScope()
BottomSheetScaffold(
scaffoldState = scaffoldState,
sheetContent = {
// Sheet content
},
floatingActionButton = {
ExtendedFloatingActionButton(
text = { Text("Expand or collapse sheet") },
onClick = {
scope.launch {
scaffoldState.bottomSheetState.apply {
if (isCollapsed) expand() else collapse()
}
}
}
)
}
) {
// Screen content
}
モーダル ボトムシートを実装する場合は ModalBottomSheetLayout
コンポーザブルを使用できます。
val sheetState = rememberModalBottomSheetState(
ModalBottomSheetValue.Hidden
)
ModalBottomSheetLayout(
sheetState = sheetState,
sheetContent = {
// Sheet content
}
) {
// Screen content
}
背景
背景を実装する場合は BackdropScaffold
コンポーザブルを使用できます。
BackdropScaffold(
appBar = {
// Top app bar
},
backLayerContent = {
// Back layer content
},
frontLayerContent = {
// Front layer content
}
)
BackdropScaffold
は他にさまざまな背景パラメータを受け入れます。たとえば peekHeight
パラメータと headerHeight
パラメータで、背面レイヤのピークの高さと、前面レイヤの非アクティブの最小の高さを設定できます。gesturesEnabled
パラメータで、背景がドラッグに応答するかどうかを切り替えることもできます。
BackdropScaffold(
appBar = {
// Top app bar
},
backLayerContent = {
// Back layer content
},
frontLayerContent = {
// Front layer content
},
// Defaults to BackdropScaffoldDefaults.PeekHeight
peekHeight = 40.dp,
// Defaults to BackdropScaffoldDefaults.HeaderHeight
headerHeight = 60.dp,
// Defaults to true
gesturesEnabled = false
)
プログラムによる背景の表示と非表示は、BackdropScaffoldState
を介して行います。rememberBackdropScaffoldState
を使用して、scaffoldState
パラメータで BackdropScaffold
に渡す必要のある BackdropScaffoldState
のインスタンスを作成できます。BackdropScaffoldState
は、現在の背景の状態に関連するプロパティだけでなく、reveal
関数と conceal
関数へのアクセスを提供します。これらの suspend 関数は CoroutineScope
を必要とし(たとえば rememberCoroutineScope
を使用)、UI イベントに応じて呼び出すことができます。
val scaffoldState = rememberBackdropScaffoldState(
BackdropValue.Concealed
)
val scope = rememberCoroutineScope()
BackdropScaffold(
scaffoldState = scaffoldState,
appBar = {
TopAppBar(
title = { Text("Backdrop") },
navigationIcon = {
if (scaffoldState.isConcealed) {
IconButton(
onClick = {
scope.launch { scaffoldState.reveal() }
}
) {
Icon(
Icons.Default.Menu,
contentDescription = "Menu"
)
}
} else {
IconButton(
onClick = {
scope.launch { scaffoldState.conceal() }
}
) {
Icon(
Icons.Default.Close,
contentDescription = "Close"
)
}
}
},
elevation = 0.dp,
backgroundColor = Color.Transparent
)
},
backLayerContent = {
// Back layer content
},
frontLayerContent = {
// Front layer content
}
)