SwiftUI : Viewのプロパティを変更する

3 min read読了の目安(約3300字

環境

この記事の情報は以下のバージョンで動作確認しています。

  • Xcode 12.3 (12C33)
  • Swift 5.3.2

概要

SwiftUIのViewはstructであるため、通常は保持するプロパティを変更することができませんが、以下に紹介するプロパティの宣言時に使えるSwiftUIのカスタム属性を使うことで可能になります。

  • @State
  • @ObserverdObjects
  • @EnvironmentObject

どれを使用したら良いのかは、構成や状況にもよるため実装に合わせてうまく使い分けてください。

@State

プロパティの宣言時に @State を先頭に付与することで View から使用が可能になります。
プロパティを使用する場合は、プロパティの先頭に $ を付与します。

以下、使用例です。

struct ContentView: View {
   @State var on: Bool = true

   var body: some View {
       VStack {
           Toggle("Switch", isOn: $on)
       }
   }
}

プロパティ on が true の場合は Toggle がONで表示され、

プロパティ on が false の場合は Toggle がOFFで表示されました。
これで プロパティの状態が View内で使用することができました。

@ObserverdObjects

@State はプロパティ単一に設定するカスダム属性ですが、@ObserverdObjects はオブジェクト丸ごとをViewからのプロパティで使用可能にするカスタム属性です。複数のプロパティを状態管理する必要がある場合に、こちらを使うと便利です。

@ObserverdObjects 付与するオブジェクトは ObservableObjectプロトコルに準拠する必要があります。
また、監視するプロパティは@Publishedを付与します。

以下、使用例です。

class User : ObservableObject {
   @Published var name: String = "Yamada"
   @Published var age: Int = 30
}

struct UserView: View {
   @ObservedObject var user: User

   var body: some View {
       HStack {
           Text(user.name)
           Text(user.age.description)
       }
   }
}

struct UserView_Previews: PreviewProvider {
   static var previews: some View {
       UserView(user: User())
   }
}

オブジェクト内のプロパティの状態を View内で使用することができました。

クラスとして定義するため複数のViewで使い回すことができるメリットがありますが、 View生成時に ObserverdObjectに準拠したクラス(オブジェクト)を指定する必要があります。

@EnvironmentObject

@ObserverdObjects と似ているカスタム属性ですが、ObserverdObject プロトコルに準拠したオブジェクトをアプリケーション全体で共有参照するために使用するカスタム属性です。

@EnvironmentObject 付与するオブジェクトは ObservableObjectプロトコルに準拠する必要があります。
また、監視するプロパティは@Publishedを付与します。

以下、使用例です。

class User : ObservableObject {
   @Published var name: String = "Yamada"
   @Published var age: Int = 30
   @Published var height: Double = 175.5
}

struct UserView: View {
   @EnvironmentObject var user: User

   var body: some View {
       HStack {
           Text(user.name)
           Slider(value: self.$user.height, in: 0...200)
       }
   }
}

struct UserView2: View {
   @EnvironmentObject var user: User

   var body: some View {
       HStack {
           Text(self.user.height.description)
       }
   }
}

struct MainView: View {
   var body: some View {
       VStack {
           UserView()
           UserView2()
       }
       .environmentObject(User())
   }
}

@main
struct HelloWorldApp: App {
   var body: some Scene {
       WindowGroup {
           MainView().environmentObject(User())
       }
   }
}

Slider と Text は異なるView である場合に、Sliderを動かすと、

同プロパティを参照しているTextも連動して動作します。
正しく異なるView間でプロパティの値が共有されていることができます。

まとめ

@State @ObserverdObjects @EnvironmentObject
管理可能プロパティ数 1のみ 複数 複数
使用範囲 View内 View内 アプリケーション内

以上、SwiftUIのViewのプロパティを変更する方法を紹介しました。
どれを使用するかは構成や状況にもよるため実装に合わせて最適な実装方法を選定してください。