MENU

【SwiftUI入門】ToolbarItemの使い方を初心者向けに徹底解説

SwiftUIでアプリを開発していると、ナビゲーションバーにボタンやメニューを追加したい場面がよくあります。そんなときに活躍するのがToolbarItemです。

本記事では、SwiftUI初心者の方でもすぐに使えるよう、ToolbarItemの基本から実践的な使い方まで、豊富なサンプルコード付きで詳しく解説します。

目次

ToolbarItemとは?

ToolbarItemは、SwiftUIでナビゲーションバーやツールバーにボタンなどのUI要素を配置するための機能です。iOS、iPadOS、macOSなど、各プラットフォームに適した位置に自動的に配置してくれます。

こんな場面で使います

  • ナビゲーションバーに「保存」「編集」ボタンを追加
  • 右上にメニューアイコンを配置
  • リストに「追加」ボタンを設置
  • 設定画面への遷移ボタンを実装

基本的な使い方

まずは最もシンプルな使い方から見ていきましょう。

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("メインコンテンツ")
                .navigationTitle("ホーム")
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button("追加") {
                            print("追加ボタンがタップされました")
                        }
                    }
                }
        }
    }
}

この例では、ナビゲーションバーの右上に「追加」ボタンが表示されます。

基本構文の説明

.toolbar {
    ToolbarItem(placement: .配置位置) {
        // ここにボタンやビューを配置
    }
}

  • toolbar: ツールバーを定義するモディファイア
  • ToolbarItem: ツールバー内の個々のアイテム
  • placement: アイテムを配置する位置を指定

配置位置(placement)の種類と使い分け

placementパラメータで、ToolbarItemをどこに配置するか指定できます。よく使う配置位置を見ていきましょう。

navigationBarTrailing(右上)

ナビゲーションバーの右側に配置されます。最もよく使われる位置です。

struct TrailingExample: View {
    var body: some View {
        NavigationView {
            Text("コンテンツ")
                .navigationTitle("サンプル")
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button(action: {
                            print("保存")
                        }) {
                            Image(systemName: "square.and.arrow.down")
                        }
                    }
                }
        }
    }
}

使用例: 保存ボタン、共有ボタン、設定ボタン

navigationBarLeading(左上)

ナビゲーションバーの左側に配置されます。

struct LeadingExample: View {
    var body: some View {
        NavigationView {
            Text("コンテンツ")
                .navigationTitle("サンプル")
                .toolbar {
                    ToolbarItem(placement: .navigationBarLeading) {
                        Button("キャンセル") {
                            print("キャンセル")
                        }
                    }
                }
        }
    }
}

使用例: キャンセルボタン、メニューボタン、戻るボタンの補助

principal(中央)

ナビゲーションバーの中央に配置されます。カスタムタイトルを表示したい場合に便利です。

struct PrincipalExample: View {
    var body: some View {
        NavigationView {
            Text("コンテンツ")
                .toolbar {
                    ToolbarItem(placement: .principal) {
                        VStack {
                            Text("カスタムタイトル")
                                .font(.headline)
                            Text("サブタイトル")
                                .font(.caption)
                                .foregroundColor(.gray)
                        }
                    }
                }
        }
    }
}

使用例: カスタムデザインのタイトル、検索バー

primaryAction(プライマリアクション)

プラットフォームに応じた主要な操作位置に配置されます。

struct PrimaryActionExample: View {
    var body: some View {
        NavigationView {
            Text("コンテンツ")
                .navigationTitle("タスク")
                .toolbar {
                    ToolbarItem(placement: .primaryAction) {
                        Button("完了") {
                            print("完了")
                        }
                    }
                }
        }
    }
}

使用例: 完了ボタン、送信ボタン

複数のToolbarItemを配置する

複数のボタンをツールバーに配置することもできます。

import SwiftUI

struct MultipleItemsView: View {
    @State private var showAlert = false
    @State private var favorited = false
    
    var body: some View {
        NavigationView {
            List(1...20, id: \.self) { number in
                Text("項目 \(number)")
            }
            .navigationTitle("リスト")
            .toolbar {
                // 左側にメニューボタン
                ToolbarItem(placement: .navigationBarLeading) {
                    Button(action: {
                        print("メニュー")
                    }) {
                        Image(systemName: "line.3.horizontal")
                    }
                }
                
                // 右側に追加ボタン
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {
                        print("追加")
                    }) {
                        Image(systemName: "plus")
                    }
                }
                
                // 右側にお気に入りボタン
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {
                        favorited.toggle()
                    }) {
                        Image(systemName: favorited ? "star.fill" : "star")
                            .foregroundColor(favorited ? .yellow : .gray)
                    }
                }
                
                // 右側に設定ボタン
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {
                        showAlert = true
                    }) {
                        Image(systemName: "gear")
                    }
                }
            }
            .alert("設定", isPresented: $showAlert) {
                Button("OK") { }
            }
        }
    }
}

このように、複数のToolbarItemを記述することで、様々なボタンを配置できます。

ToolbarItemGroupで複数をまとめる

関連する複数のアイテムをグループ化したい場合は、ToolbarItemGroupを使います。

import SwiftUI

struct ToolbarGroupExample: View {
    var body: some View {
        NavigationView {
            Text("コンテンツ")
                .navigationTitle("写真")
                .toolbar {
                    ToolbarItemGroup(placement: .navigationBarTrailing) {
                        Button(action: {
                            print("共有")
                        }) {
                            Image(systemName: "square.and.arrow.up")
                        }
                        
                        Button(action: {
                            print("お気に入り")
                        }) {
                            Image(systemName: "heart")
                        }
                        
                        Button(action: {
                            print("その他")
                        }) {
                            Image(systemName: "ellipsis.circle")
                        }
                    }
                }
        }
    }
}

ToolbarItemGroupを使うと、複数のボタンを1つのグループとして管理でき、コードも読みやすくなります。

実践例1: 編集可能なリスト

実際のアプリでよく使われる、編集モード付きリストの実装例です。

import SwiftUI

struct EditableListView: View {
    @State private var items = ["りんご", "バナナ", "オレンジ", "ぶどう", "いちご"]
    @State private var editMode: EditMode = .inactive
    @State private var showingAddAlert = false
    @State private var newItemName = ""
    
    var body: some View {
        NavigationView {
            List {
                ForEach(items, id: \.self) { item in
                    Text(item)
                }
                .onDelete(perform: deleteItems)
                .onMove(perform: moveItems)
            }
            .navigationTitle("フルーツリスト")
            .environment(\.editMode, $editMode)
            .toolbar {
                // 左側: 編集ボタン
                ToolbarItem(placement: .navigationBarLeading) {
                    Button(editMode == .active ? "完了" : "編集") {
                        withAnimation {
                            editMode = editMode == .active ? .inactive : .active
                        }
                    }
                }
                
                // 右側: 追加ボタン
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {
                        showingAddAlert = true
                    }) {
                        Image(systemName: "plus.circle.fill")
                    }
                    .disabled(editMode == .active)
                }
            }
            .alert("新しいフルーツを追加", isPresented: $showingAddAlert) {
                TextField("フルーツ名", text: $newItemName)
                Button("追加") {
                    if !newItemName.isEmpty {
                        items.append(newItemName)
                        newItemName = ""
                    }
                }
                Button("キャンセル", role: .cancel) {
                    newItemName = ""
                }
            }
        }
    }
    
    func deleteItems(at offsets: IndexSet) {
        items.remove(atOffsets: offsets)
    }
    
    func moveItems(from source: IndexSet, to destination: Int) {
        items.move(fromOffsets: source, toOffset: destination)
    }
}

この例では、編集モードの切り替えと、新しいアイテムの追加機能を実装しています。

実践例2: メモアプリ風のツールバー

メモアプリのような、充実したツールバーの実装例です。

import SwiftUI

struct NoteEditorView: View {
    @State private var noteText = ""
    @State private var showingShare = false
    @State private var isBold = false
    @State private var isItalic = false
    
    var body: some View {
        NavigationView {
            VStack {
                TextEditor(text: $noteText)
                    .padding()
            }
            .navigationTitle("新規メモ")
            .toolbar {
                // 左側: 閉じるボタン
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("閉じる") {
                        print("閉じる")
                    }
                }
                
                // 右側: 操作ボタングループ
                ToolbarItemGroup(placement: .navigationBarTrailing) {
                    Button(action: {
                        showingShare = true
                    }) {
                        Image(systemName: "square.and.arrow.up")
                    }
                    
                    Button("保存") {
                        print("保存しました")
                    }
                }
                
                // 下部: フォーマットツール(iOS 16+)
                ToolbarItemGroup(placement: .bottomBar) {
                    Button(action: {
                        isBold.toggle()
                    }) {
                        Image(systemName: "bold")
                            .foregroundColor(isBold ? .blue : .gray)
                    }
                    
                    Button(action: {
                        isItalic.toggle()
                    }) {
                        Image(systemName: "italic")
                            .foregroundColor(isItalic ? .blue : .gray)
                    }
                    
                    Spacer()
                    
                    Button(action: {
                        print("画像を追加")
                    }) {
                        Image(systemName: "photo")
                    }
                    
                    Button(action: {
                        print("チェックリスト追加")
                    }) {
                        Image(systemName: "checklist")
                    }
                }
            }
            .sheet(isPresented: $showingShare) {
                Text("共有画面")
            }
        }
    }
}

カスタムボタンのデザイン

ToolbarItemの中で、カスタムデザインのボタンを作成することもできます。

import SwiftUI

struct CustomToolbarButtonView: View {
    @State private var notificationCount = 5
    
    var body: some View {
        NavigationView {
            Text("コンテンツ")
                .navigationTitle("ホーム")
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button(action: {
                            print("通知を確認")
                        }) {
                            ZStack(alignment: .topTrailing) {
                                Image(systemName: "bell.fill")
                                    .font(.title3)
                                
                                if notificationCount > 0 {
                                    Text("\(notificationCount)")
                                        .font(.caption2)
                                        .foregroundColor(.white)
                                        .padding(4)
                                        .background(Color.red)
                                        .clipShape(Circle())
                                        .offset(x: 8, y: -8)
                                }
                            }
                        }
                    }
                }
        }
    }
}

このように、バッジ付きの通知アイコンなど、カスタムデザインも実装できます。

プラットフォーム別の表示の違い

ToolbarItemの大きな利点は、各プラットフォームに適した位置に自動配置されることです。

iOS/iPadOS

  • navigationBarTrailing: ナビゲーションバーの右上
  • navigationBarLeading: ナビゲーションバーの左上
  • bottomBar: 画面下部のツールバー

macOS

  • ウィンドウ上部のツールバーに表示
  • より多くのアイテムを横並びで表示可能

watchOS

  • 画面サイズに応じて最適化された位置に表示
  • シンプルなアイコンが推奨される

同じコードで、各プラットフォームに最適なUIを実現できます。

よくあるエラーと解決方法

エラー1: NavigationViewがない

// ❌ 悪い例:NavigationViewなしでtoolbarを使用
struct ContentView: View {
    var body: some View {
        Text("コンテンツ")
            .toolbar {  // これは表示されない
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("保存") { }
                }
            }
    }
}

// ✅ 良い例:NavigationViewで囲む
struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("コンテンツ")
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button("保存") { }
                    }
                }
        }
    }
}

toolbarモディファイアは、NavigationViewまたはNavigationStack内で使用する必要があります。

エラー2: ボタンが表示されない

// ❌ 悪い例:navigationTitleがない
NavigationView {
    Text("コンテンツ")
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button("保存") { }
            }
        }
}

// ✅ 良い例:navigationTitleを設定
NavigationView {
    Text("コンテンツ")
        .navigationTitle("ホーム")  // これが重要
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button("保存") { }
            }
        }
}

ナビゲーションバーを表示するには、navigationTitleの設定が必要です。

エラー3: @Stateの宣言忘れ

// ❌ 悪い例:状態管理ができない
var isEditing = false

.toolbar {
    ToolbarItem(placement: .navigationBarTrailing) {
        Button("編集") {
            isEditing.toggle()  // ビューが更新されない
        }
    }
}

// ✅ 良い例:@Stateを使用
@State private var isEditing = false

.toolbar {
    ToolbarItem(placement: .navigationBarTrailing) {
        Button("編集") {
            isEditing.toggle()  // ビューが正しく更新される
        }
    }
}

NavigationStack(iOS 16+)での使用

iOS 16以降では、NavigationViewの代わりにNavigationStackを使用できます。

import SwiftUI

struct NavigationStackExample: View {
    var body: some View {
        NavigationStack {
            List(1...20, id: \.self) { number in
                NavigationLink("項目 \(number)", value: number)
            }
            .navigationTitle("リスト")
            .navigationDestination(for: Int.self) { number in
                Text("項目 \(number)の詳細")
                    .navigationTitle("詳細")
                    .toolbar {
                        ToolbarItem(placement: .navigationBarTrailing) {
                            Button("共有") {
                                print("共有")
                            }
                        }
                    }
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("設定") {
                        print("設定")
                    }
                }
            }
        }
    }
}

NavigationStackを使うと、より現代的なナビゲーションが実装できます。

パフォーマンスのベストプラクティス

ToolbarItemを効率的に使うためのポイントをまとめます。

1. 適切な数のアイテムを配置

// ✅ 良い例:必要最小限のボタン(3〜4個程度)
.toolbar {
    ToolbarItemGroup(placement: .navigationBarTrailing) {
        Button("共有") { }
        Button("編集") { }
        Button("削除") { }
    }
}

// ❌ 悪い例:ボタンが多すぎる(5個以上)
// ユーザーが混乱する可能性がある

2. SF Symbolsの活用

// ✅ 良い例:わかりやすいアイコンを使用
Button(action: {}) {
    Image(systemName: "square.and.arrow.up")  // 共有アイコン
}

// より良い例:アクセシビリティラベルを追加
Button(action: {}) {
    Image(systemName: "square.and.arrow.up")
}
.accessibilityLabel("共有")

3. 状態に応じた表示制御

@State private var isProcessing = false

.toolbar {
    ToolbarItem(placement: .navigationBarTrailing) {
        if isProcessing {
            ProgressView()
        } else {
            Button("保存") {
                isProcessing = true
                // 保存処理
            }
        }
    }
}

まとめ

ToolbarItemは、SwiftUIでナビゲーションバーやツールバーを簡単にカスタマイズできる強力な機能です。

覚えておきたいポイント

  • NavigationViewまたはNavigationStack内で使用する
  • placementパラメータで配置位置を指定できる
  • 複数のアイテムはToolbarItemGroupでまとめられる
  • プラットフォームごとに最適な位置に自動配置される
  • SF Symbolsを使うと美しいアイコンが簡単に使える
  • @Stateで状態管理を忘れずに

主要な配置位置まとめ

placement位置用途
.navigationBarTrailing右上保存、共有、設定ボタン
.navigationBarLeading左上キャンセル、メニューボタン
.principal中央カスタムタイトル、検索バー
.primaryActionプライマリ位置完了、送信ボタン
.bottomBar下部フォーマットツール、追加機能

この記事で紹介したサンプルコードを実際にXcodeで動かして、ToolbarItemの使い方をマスターしましょう。ナビゲーションバーのカスタマイズは、アプリの使いやすさを大きく左右する重要な要素です!

参考リンク

プログラミングの独学におすすめ
プログラミング言語の人気オンラインコース
独学でプログラミングを学習している方で、エラーなどが発生して効率よく勉強ができないと悩む方は多いはず。Udemyは、プロの講師が動画で実際のプログラムを動かしながら教えてくれるオンライン講座です。講座の価格は、セール期間中には専門書籍を1冊買うよりも安く済むことが多いです。新しく学びたいプログラミング言語がある方は、ぜひUdemyでオンライン講座を探してみてください。
目次