タイトル: ツールバーの設置とボタンの追加
SEOタイトル: SwiftUI / UIKit ツールバー設置完全ガイド
| この記事の要点 |
|
SwiftUI のツールバー
iOS 14 / macOS 11 から導入された .toolbar モディファイアで宣言的にツールバーを構築します。NavigationView / NavigationStack の上下バーや、独立ウィンドウのツールバーに使えます。
1. 最小例 (NavigationStack + ナビゲーションバー右)
import SwiftUI
struct ContentView: View {
@State private var items: [String] = []
var body: some View {
NavigationStack {
List(items, id: \.self) { Text($0) }
.navigationTitle("リスト")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
items.append("Item \(items.count + 1)")
} label: {
Image(systemName: "plus")
}
.accessibilityLabel("追加")
}
}
}
}
}
2. placement の種類
| placement | 表示位置 |
|---|---|
.navigationBarLeading | ナビゲーションバー左端 |
.navigationBarTrailing | ナビゲーションバー右端 |
.principal | ナビゲーションバー中央 (タイトル位置) |
.bottomBar | 画面下部のツールバー |
.topBarLeading / .topBarTrailing | iOS 17+ の汎用版 |
.keyboard | キーボード上に表示 (テキスト入力時) |
.confirmationAction | OK / 完了相当 (右側) |
.cancellationAction | キャンセル相当 (左側) |
.destructiveAction | 削除系 |
3. 複数ボタンを並べる (ToolbarItemGroup)
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button { share() } label: {
Image(systemName: "square.and.arrow.up")
}
Button { favorite() } label: {
Image(systemName: "star")
}
Menu {
Button("並び替え") { sort() }
Button("フィルタ") { filter() }
Divider()
Button("削除", role: .destructive) { delete() }
} label: {
Image(systemName: "ellipsis.circle")
}
}
}
4. 下部バー (bottomBar) + Spacer
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Button("削除", role: .destructive) { delete() }
Spacer() // ★ 左右に分離
Text("\(items.count) 件")
Spacer()
Button("追加") { add() }
}
}
// 下部バーを常に表示
.toolbarBackground(.visible, for: .bottomBar)
.toolbarBackground(Color.blue, for: .bottomBar)
5. シート/モーダル内のキャンセル・完了
struct EditView: View {
@Environment(\.dismiss) var dismiss
@State var name: String = ""
var body: some View {
NavigationStack {
Form {
TextField("名前", text: $name)
}
.navigationTitle("編集")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("キャンセル") { dismiss() }
}
ToolbarItem(placement: .confirmationAction) {
Button("保存") {
save()
dismiss()
}
.disabled(name.isEmpty)
}
}
}
}
}
6. キーボード上のツールバー
@FocusState private var focused: Bool
TextField("入力", text: $text)
.focused($focused)
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button("完了") { focused = false }
}
}
7. principal でカスタムタイトル
.toolbar {
ToolbarItem(placement: .principal) {
HStack {
Image(systemName: "wifi")
Text("接続中")
.font(.headline)
}
}
}
.navigationBarTitleDisplayMode(.inline)
UIKit のツールバー
UIKit では UINavigationItem と UIToolbar の 2 系統があります。
8. ナビゲーションバーのボタン (UIKit)
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
title = "リスト"
// 右ボタン
navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .add,
target: self,
action: #selector(addTapped)
)
// 左ボタン (カスタム画像)
let cancel = UIBarButtonItem(
image: UIImage(systemName: "xmark"),
style: .plain,
target: self,
action: #selector(cancelTapped)
)
navigationItem.leftBarButtonItem = cancel
// 複数ボタン
navigationItem.rightBarButtonItems = [
UIBarButtonItem(systemItem: .action, primaryAction: nil),
UIBarButtonItem(systemItem: .bookmarks, primaryAction: nil),
]
}
@objc func addTapped() { /* ... */ }
@objc func cancelTapped() { dismiss(animated: true) }
}
9. UIToolbar (下部ツールバー)
let toolbar = UIToolbar()
toolbar.translatesAutoresizingMaskIntoConstraints = false
let trash = UIBarButtonItem(barButtonSystemItem: .trash, target: self, action: #selector(deleteTapped))
let flex = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let add = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addTapped))
toolbar.items = [trash, flex, add]
view.addSubview(toolbar)
NSLayoutConstraint.activate([
toolbar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
toolbar.trailingAnchor.constraint(equalTo: view.trailingAnchor),
toolbar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
])
10. Storyboard でツールバー設置
- Object Library から Navigation Item または Toolbar をドラッグ
- Bar Button Item を Navigation Bar 上にドロップ
- Attributes Inspector で System Item を選択 (Add / Done / Cancel など)
- Control + Drag でアクションを ViewController に接続
SF Symbols 一覧
iOS 13+ に標準搭載される 5,000+ 種類のベクターアイコン。
| 用途 | シンボル名 |
|---|---|
| 追加 | plus / plus.circle |
| 削除 | trash / minus |
| 共有 | square.and.arrow.up |
| 編集 | pencil / square.and.pencil |
| お気に入り | star / heart |
| 戻る | chevron.left |
| その他 | ellipsis / ellipsis.circle |
| 検索 | magnifyingglass |
Mac のSF Symbols アプリで全シンボルを検索できます。
アクセシビリティ対応
Button { add() } label: {
Image(systemName: "plus")
}
.accessibilityLabel("新しい項目を追加") // VoiceOver 読み上げ
.accessibilityHint("タップでアイテムを追加") // ヒント (二度押し時)
.accessibilityAddTraits(.isButton) // 役割明示
FAQ
Q: ツールバーが表示されない
A: NavigationStack / NavigationView で包んでいますか? .toolbar は親に navigation context が必要です。
Q: bottomBar が出ない
A: .toolbar(.visible, for: .bottomBar) を追加。または TabView 内では別途設計。
Q: Image(systemName:) が表示されない
A: シンボル名が存在しないか、iOS バージョン不足。SF Symbols アプリで確認し、if #available(iOS 17, *) でガード。
Q: ボタンに色を付けたい
A: .tint(.red) または .foregroundStyle(.red)。ナビゲーションバー全体は .toolbarBackground(.blue, for: .navigationBar)。