0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

改めてSwiftUIのViewの基礎についておさらいするメモ

Last updated at Posted at 2024-07-07

本記事について

本記事は、以下のセッションを見て改めて重要だと思った内容を復習しながらメモしたものです。

イントロ

SwiftUIは新しいアプリや機能を構築する際に最適なツールと述べています。

その理由は、下記の通りです。

Rich Feature Set

SwiftUIは豊富な機能セットを提供しています。開発者はさまざまな機能を簡単に実装することができます。

Less Code

これらの豊富な機能を実装するために必要なコード量が少なくて済みます。

Incremental Adoption

アプリ全体をSwiftUIで書く必要はありません。
既存のアプリに徐々にSwiftUIを取り入れることができ、必要な部分だけを更新することが可能です。

Viewの基礎

SwiftUIのViewには3つの特徴があります。

  1. Declarative(宣言的)
  2. Compositional(構成型)
  3. State-Driven(状態駆動)

1. Declarative(宣言的)

UIKitのような命令的な実装では、ゴールに到達するまでの各ステップが必要ですが、宣言的な実装では、期待する結果に焦点を当てます。SwiftUIは命令的、宣言的の2つの要素を持っています。

下記に具体的な実装例を示します。

実現したいUIを宣言

Text("test")

Image(systemName: "gear")

Button("Tap") {
  // ボタン押した時の処理
}

HStackやVStackなどを使えば、それぞれのパーツの組み合わせを作る

HStack {
    Image(systemName: "globe")
    Text("Hello")
}

Listなどの他のコンテナにも適用

List(0..<5) {_ in
    HStack {
        Image(systemName: "globe")
        Text("Hello")
    }
}

宣言的にUIを配置して、命令的に状態の変更を加える

Button("Add money") {
    let money = Money(100)
    moneyList.append(money)
}

なぜStructなのか?

Viewは、UIの現在の状態を示し、時間とともに命令を受け取って更新されます。長期間使うインスタンスではないため、classではなくstructを使用しています。

2. Compositional(構成型)

コンテナビューの再配置が簡単

HStack {
    Label("hello", systemImage: "gear")
    
    Spacer()
    
    Text("walking")
}

HStack {
    Image("pork")
        .resizable()
        .frame(width: 50, height: 50)

    VStack(alignment: .leading) {
        Label("hello", systemImage: "gear")
        Text("walking")
    }

    Spacer()
}

View Modifierは順序に基づいて定義される

Image("dog")
    .clipShape(.circle) // 2つ目
    .shadow(radius: 20) // 3つ目
    .overlay {
        Circle().stroke(.green, lineWidth: 5) // 4つ目
    }

3. State-Driven(状態駆動)

状態が変化すると自動的に最新の状態に保つため、更新のバグを防ぐことができます。

@Stateを用いた状態管理

ボタンが押された後、内部状態でcountがインクリメントされます。
countの変化がViewに通知され、bodyを呼び出すことで値が変更されます。

struct CounterView: View {
    @State private var count: Int = 0
    
    var body: some View {
        VStack {
            Text("\(count)")
            Button("Add Count") {
                count += 1
            }
        }
    }
}

@Bindingを用いた状態管理

親子関係のViewを扱う際には、子View(CounterView)がBindingを入力として受け取るように更新します。これにより、双方向で状態変化を参照でき、親Viewの更新が同期されます。

struct CounterView: View {
    @Binding var count: Float
    var body: some View {
        VStack {
            Text("\(count)")
            Button("Add Count") {
                count += 0.1
            }
        }
    }
}

struct ContentView: View {
    @State private var count: Float = 0.0
    var body: some View {
        VStack {
            Gauge(value: count, in: 0...1) {
                Text("Counter")
            }
            
            CounterView(count: $count)
        }
    }
}

最後に

WWDC24で基礎的なセッションが公開されましたが、改めて見ると実は知らなかった要素や、感覚的には理解していたものの言語化できていなかった要素があり、良い復習になりました。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?