SwiftUI の safeAreaInset・ignoresSafeArea でセーフエリアを制御する
iOS アプリではセーフエリア(ノッチやホームインジケーターを避けた安全な領域)を意識したレイアウトが不可欠です。SwiftUI はデフォルトでセーフエリア内にコンテンツを配置しますが、ignoresSafeArea で意図的にはみ出させたり、safeAreaInset で追加の余白を設けたりすることで、より柔軟なレイアウトを実現できます。
セーフエリアの基本動作
SwiftUI のビューはデフォルトでセーフエリア内に収まります。
VStack {
Text("上端")
Spacer()
Text("下端")
}このコードでは「上端」はステータスバーの下に、「下端」はホームインジケーターの上に配置されます。開発者が特別な指定をしなくても安全な位置にコンテンツが表示される仕組みです。
ignoresSafeArea でセーフエリアを無視する
背景色や画像を画面端まで広げたいときには ignoresSafeArea を使います。
ZStack {
Color.blue
.ignoresSafeArea()
VStack {
Text("コンテンツは安全な位置に")
.foregroundColor(.white)
Spacer()
}
}Color にだけ ignoresSafeArea を付け、テキストを含む VStack には付けていません。こうすることで、背景色は画面全体に広がりつつ、コンテンツはセーフエリア内に留まります。
edges と regions パラメータ
ignoresSafeArea は、無視するセーフエリアの辺と種類を細かく指定できます。
// 下端だけセーフエリアを無視
ScrollView {
content
}
.ignoresSafeArea(edges: .bottom)
// キーボード領域のみ無視
TextField("入力", text: $text)
.ignoresSafeArea(.keyboard, edges: .bottom).top、.bottom、.leading、.trailing、.all などを指定し、どの辺のセーフエリアを無視するかを選べる。デフォルトは .all になっている。
.container(ノッチやホームインジケーター)と .keyboard(キーボード)を区別できる。キーボード表示時のレイアウト制御に使うことが多い。
safeAreaInset でカスタム余白を追加する
iOS 15 で導入された safeAreaInset は、セーフエリアに追加のスペースを挿入するモディファイアです。フローティングボタンやカスタムツールバーの領域を確保するのに最適です。
ScrollView {
ForEach(0..<30) { index in
Text("アイテム \(index)")
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
}
}
.safeAreaInset(edge: .bottom) {
HStack {
Button("キャンセル") { }
.buttonStyle(.bordered)
Spacer()
Button("保存") { }
.buttonStyle(.borderedProminent)
}
.padding()
.background(.ultraThinMaterial)
}safeAreaInset で下端に固定バーを配置すると、ScrollView のコンテンツはそのバーの分だけ余白を確保します。最後のアイテムまでスクロールしてもバーに隠れることがありません。
overlay との違い
フローティングボタンの実装で overlay を使う方法もありますが、safeAreaInset とは挙動が異なります。
ビューの上に重ねるだけで、スクロールコンテンツの余白は調整されない。最後のアイテムがバーに隠れてしまう
セーフエリアを拡張するため、スクロールコンテンツが自動的にバーの高さ分だけ余白を確保する
safeAreaInset は単に「ビューを配置する」だけでなく「セーフエリア自体を変更する」ため、ScrollView やリストと組み合わせたときに正しい余白が保たれます。
複数の safeAreaInset を組み合わせる
safeAreaInset は複数回適用できます。上端と下端それぞれにバーを追加することも可能です。
List(items) { item in
ItemRow(item: item)
}
.safeAreaInset(edge: .top) {
SearchBar(text: $searchText)
.padding(.horizontal)
.background(.bar)
}
.safeAreaInset(edge: .bottom) {
BottomToolbar()
.background(.bar)
}上端に検索バー、下端にツールバーを配置しつつ、リストのスクロール領域はそれぞれの高さを自動的に避けてくれます。カスタム UI を構築するときの強力な選択肢として覚えておくとよいでしょう。