ScaffoldはJetpack Composeのcomposable関数で、Material Design仕様に従った基本的な画面構造を実装します。ScaffoldはTopAppBar、BottomBar、FloatingActionButton、Drawer、Snackbarのスロットを提供します。Google Android Documentation, 2025によると、ScaffoldはMaterial Designシステムコンポーネントのマージンを管理するため、Composeアプリケーションのほとんどの画面で必須の要素です。
重要なポイント
Scaffoldは、Material Design仕様に従って画面の枠組みを実装するcomposable関数です。Scaffoldは従来の意味でのコンテナではなく、画面上の複数の標準Materialコンポーネントの配置を調整するレイアウトマネージャーです。
ScaffoldはTopAppBar、BottomBar、FloatingActionButtonのマージンを管理し、さらにシステム要素(ステータスバーとナビゲーションバー)も管理します。これにより、コンテンツがシステム要素と重ならず、Material Designのガイドラインに準拠することが保証されます。
Material Design Guidelines, 2025によると、Scaffoldはすべてのアプリ画面のルート要素であるべきです。これはViewシステムの古いCoordinatorLayoutを置き換え、画面レイアウトを構築するためのよりシンプルで宣言的なAPIを提供します。
Scaffoldはmodifier、scaffoldState、topBar、bottomBar、floatingActionButton、drawerContent、snackbarHost、contentのパラメータを受け入れます。contentパラメータはPaddingValues(メインコンテンツが考慮すべきマージン)を受け取ります。
@Composable
fun BasicScaffold() {
Scaffold(
topBar = {
TopAppBar(
title = { Text("ホーム") }
)
},
floatingActionButton = {
FloatingActionButton(onClick = {}) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
}
) { innerPadding ->
Column(
modifier = Modifier.padding(innerPadding)
) {
Text("メインコンテンツ")
}
}
}
topBarはアプリのトップバーを配置するスロットで、通常はTopAppBarまたはLargeTopAppBarです。ScaffoldはコンテンツがtopBarと重ならないように、innerPaddingに自動的にマージンを追加します。TopAppBarにはタイトル、ナビゲーションアイコン、アクションを含めることができます。
bottomBarは下部ナビゲーションバーのスロットです。BottomNavigation、BottomAppBar、NavigationBarをサポートしています。ScaffoldはコンテンツのinnerPaddingを計算する際にbottomBarの高さを考慮します。Material Design Guidelines, 2025によると、bottomBarは3~5つのナビゲーションポイントを持つ画面で使用すべきです。
floatingActionButtonはフローティングアクションボタンのスロットです。ScaffoldはMaterial Design仕様に従ってFABを自動的に配置します(正しいマージンで右下隅)。floatingActionButtonPositionを使用すると、FABを画面の下端中央に移動できます。
この例では、Scaffoldがすべての主要スロットを使用しています:タイトル付きのTopAppBar、3つのナビゲーション項目を持つBottomBar、メインアクション用のFloatingActionButton。
@Composable
fun FullScaffold() {
Scaffold(
topBar = {
TopAppBar(
title = { Text("アプリ") },
navigationIcon = {
IconButton(onClick = {}) {
Icon(Icons.Default.Menu, "Menu")
}
}
)
},
bottomBar = {
NavigationBar {
NavigationBarItem(
icon = { Icon(Icons.Default.Home, "ホーム") },
label = { Text("Home") },
selected = true,
onClick = {}
)
NavigationBarItem(
icon = { Icon(Icons.Default.Search, "検索") },
label = { Text("Search") },
selected = false,
onClick = {}
)
}
},
floatingActionButton = {
FloatingActionButton(onClick = {}) {
Icon(Icons.Default.Add, "Add")
}
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
Text("画面コンテンツ")
}
}
}
ScaffoldStateはDrawerStateとSnackbarHostStateを組み合わせたScaffoldの状態オブジェクトです。DrawerStateはサイドメニューの開閉を管理し、SnackbarHostStateはSnackbarの表示と非表示を管理します。状態はrememberScaffoldState()を使用して作成され、scaffoldStateパラメータに渡されます。
DrawerStateはプログラムによるDrawer制御のためのopenメソッドとcloseメソッドを提供します。Drawerの状態は開く、閉じる、部分的に開くのいずれかです。drawerGesturesEnabledを使用すると、Drawerを開くスワイプジェスチャーを無効にし、ボタンによるプログラム的な開封のみを残すことができます。
SnackbarHostStateはSnackbar(画面下部の一時的な通知)を管理します。showSnackbarメソッドは、メッセージとオプションのアクションを持つSnackbarを表示します。Material Design Guidelines, 2025によると、Snackbarは重大な情報を含まない簡潔なメッセージに使用すべきです。
@Composable
fun ScaffoldWithDrawer() {
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
title = { Text("メニュー") },
navigationIcon = {
IconButton(onClick = {
scope.launch {
scaffoldState.drawerState.open()
}
}) {
Icon(Icons.Default.Menu, "Menu")
}
}
)
},
drawerContent = {
Column(modifier = Modifier.padding(16.dp)) {
Text("項目1")
Text("項目2")
}
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
Text("コンテンツ")
}
}
}
Scaffoldを使用した完全な画面例には、TopAppBar、BottomNavigation、FloatingActionButton、およびFAB押下時に通知を表示するSnackbarが含まれます。ScaffoldStateは状態の調整のためにすべてのコンポーネントに渡されます。
@Composable
fun MainScreen() {
val state = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = state,
topBar = {
TopAppBar(
title = { Text("IT Sectr") },
actions = {
IconButton(onClick = {}) {
Icon(Icons.Default.Notifications, "Notifications")
}
}
)
},
bottomBar = {
NavigationBar {
NavigationBarItem(icon = { Icon(Icons.Default.Home, "ホーム") },
label = { Text("Home") }, selected = true, onClick = {})
NavigationBarItem(icon = { Icon(Icons.Default.Settings, "設定") },
label = { Text("Settings") }, selected = false, onClick = {})
}
},
floatingActionButton = {
FloatingActionButton(onClick = {
scope.launch {
state.snackbarHostState.showSnackbar("完了")
}
}) {
Icon(Icons.Default.Add, "Add")
}
}
) { padding ->
Box(
modifier = Modifier.padding(padding).fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("ようこそ")
}
}
}
innerPaddingはScaffoldがcontentブロックに渡すPaddingValuesです。これらには、コンテンツがstatusBar、navigationBar、topBar、bottomBarと重なるのを防ぐために必要なマージンが含まれています。異なるデバイスで正しく表示するには、innerPaddingの使用が必須です。
Scaffoldはシステムのマージンとインストールされたスロットの高さに基づいてinnerPaddingを自動的に計算します。カメラアイ島や画面の切り欠きがあるデバイスでは、Scaffoldはステータスバーのマージンを調整します。物理ボタンがある古いデバイスでは、下部のマージンが存在しない場合があります。
Android Developers, 2024によると、innerPaddingはModifier.padding(innerPadding)を使用してコンテンツのルートコンテナに適用する必要があります。コンテンツがスクロール可能なコンテナを使用する場合、キーボードとシステムジェスチャの正しい動作のために、innerPaddingはModifier.consumeWindowInsetsを介して適用されます。
よくある質問
Scaffoldはコンテナではなく、TopAppBar、BottomBar、FAB、Drawer、Snackbarのスロットを制御し、システムコンポーネントのマージンを自動的に処理するレイアウトマネージャーです。ColumnとBoxはMaterial Designを考慮せずに要素を配置するだけです。
ScaffoldはMaterial Designコンポーネントを使用する画面で推奨されます。TopAppBar、BottomBar、FABのないシンプルな画面ではScaffoldは必須ではありませんが、innerPaddingを通じて正しいシステムマージンを提供するため、スロットがなくても有用です。
ScaffoldのscaffoldStateパラメータにScaffoldStateを渡し、コルーチン内でstate.snackbarHostState.showSnackbar(“メッセージ”)を呼び出します。Scaffoldは自動的に画面下部にSnackbarを表示します。
はい、ScaffoldはscaffoldStateが渡されない場合、デフォルトで内部状態を作成します。ただし、DrawerとSnackbarをプログラム的に制御するには、rememberScaffoldState()を使用してScaffoldStateを作成して渡す必要があります。
ScaffoldのfloatingActionButtonPositionパラメータを使用します。デフォルトではFABは右下(FabPosition.End)に配置されます。FabPosition.Centerを設定すると、FABを画面の下端中央に配置できます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。