🐡

SwiftUIビューマネジメント&データバインディング基礎

に公開

はじめに

今週学んだSwiftUIの基礎的なビュー管理とデータバインディングについて、主要ポイントを整理しました。

目次

  1. NavigationStackとナビゲーションバー
  2. モーダル表示(.sheet(isPresented:).sheet(item:)
  3. @State / @Binding / @StateObject / @ObservedObject の使い分け
  4. ViewModifierでスタイルを共通化
  5. カスタムViewの再利用とForEach
  6. ScrollViewの基礎

1. NavigationStackとナビゲーションバー

NavigationStack は画面遷移の仕組みだけでなく、タイトルバー(ナビゲーションバー)を表示するコンテナとしても使います。画面遷移が不要でも、.navigationTitle("タイトル") を効かせたい場合は必須。

NavigationStack {
    List(tasks) { task in
        Text(task)
    }
    .navigationTitle("ToDoリスト")
}

ポイント

  • 画面タイトルを表示するだけでも NavigationStack が必要
  • 後から NavigationLink を追加しやすい構造

2. モーダル表示

.sheet(isPresented:)

@State private var isShowing = false

Button("表示") { isShowing = true }
.sheet(isPresented: $isShowing) {
    DetailView()
}
  • Binding<Bool> で表示/非表示を制御
  • クロージャ引数なし

.sheet(item:)

struct Item: Identifiable { let id = UUID(); let name: String }
@State private var selectedItem: Item?

List(items) { item in
    Button(item.name) { selectedItem = item }
}
.sheet(item: $selectedItem) { item in
    DetailView(item: item)
}
  • Binding<Identifiable?> を使い、選択したモデルを渡す
  • シート閉じると自動で nil に戻る

3. プロパティラッパーの使い分け

用途 プロパティラッパー 宣言箇所
単一の値(ローカル) @State struct View の中
モデルを所有して監視 @StateObject 生成側・親ビュー
渡されたモデルを監視 @ObservedObject 子ビュー・参照のみ

例:ペット情報入力

class Pet: ObservableObject {
    @Published var name = ""
    @Published var age = ""
}

struct InputView: View {
    @StateObject private var pet = Pet()
    @State private var showInfo = false

    var body: some View {
        TextField("名前", text: $pet.name)
        Button("決定") { showInfo = true }
            .sheet(isPresented: $showInfo) {
                InfoView(pet: pet)
            }
    }
}

struct InfoView: View {
    @ObservedObject var pet: Pet
    var body: some View {
        Text("名前: \(pet.name)")
    }
}

4. ViewModifierでスタイルを共通化

struct ButtonModifier: ViewModifier {
    let bg: Color
    func body(content: Content) -> some View {
        content
            .font(.title)
            .foregroundColor(.white)
            .frame(width: 300, height: 60)
            .background(bg)
            .cornerRadius(30)
            .padding()
    }
}

// 拡張
extension View {
    func roundedButton(bg: Color) -> some View {
        modifier(ButtonModifier(bg: bg))
    }
}

// 使い方
Button("Tap Me") {}
    .roundedButton(bg: .blue)

5. カスタムViewの再利用とForEach

struct EyeView: View {
    var body: some View {
        ZStack {
            RectangleView(color: .gray, width: 90, height: 90)
            RectangleView(color: .white, width: 70, height: 70)
            RectangleView(color: .black, width: 20, height: 20)
        }
    }
}

HStack {
    RectangleView(color: .black, width: 60, height: 20)
    ForEach(0..<2) { _ in EyeView() }
    RectangleView(color: .black, width: 60, height: 20)
}
  • EyeView を再利用して左右2つを ForEach で生成

6. ScrollViewの基礎

ScrollView(.horizontal, showsIndicators: false) {
    HStack {
        ForEach(items) { item in
            ItemView(item: item)
        }
    }
}
  • .horizontal: 横方向スクロール
  • showsIndicators: false: スクロールバー非表示

以上、今週学んだSwiftUIの基礎まとめでした!次回も引き続き学習頑張ります💪

Discussion