👻

Custom Viewを利用して特定のForEach itemに独自な事件を加える

2022/02/04に公開

まずは、ForEachでいくつのボタンを作る

struct ContentView: View {
    let items = ["Forest", "Sun", "Moon", "Sea"]

    var body: some View {
        VStack {
            ForEach(items, id: \.self) { item in
                Button(item) { }
                    .buttonStyle(.borderedProminent)
            }
        }
    }
}

画面はこんな感じです

次に、クリックモーションを加える

 struct ContentView: View {
    
     let items = ["Forest", "Sun", "Moon", "Sea"]
+    @State private var animationAmount = 0.0

     var body: some View {
        
         VStack() {
             ForEach(items, id: \.self) { item in
                 Button(item) {
+                    withAnimation {
+                        animationAmount += 360
+                    }
                 }
                 .buttonStyle(.borderedProminent)
+                .rotation3DEffect(.degrees(animationAmount), axis: (x: 0, y: 1, z: 0))
                
             }
         }
     }
  }

しかしみんなが一斉に動き出してしまった、、、

クリックされたボタンだけにモーションをつけるために、Custom Viewを利用してViewを分離させる

+struct MyButton: View {   
+    var text: String
+    @State private var animationAmount = 0.0
+    
+    var body: some View {
+        Button(text) {
+            withAnimation {
+                animationAmount += 360
+            }
+        }
+        .buttonStyle(.borderedProminent)
+        .rotation3DEffect(.degrees(animationAmount), axis: (x: 0, y: 1, z: + 0))
+    }
+}

 struct ContentView: View {
    
     let items = ["Forest", "Sun", "Moon", "Sea"]
-    @State private var animationAmount = 0.0

     var body: some View {
        
         VStack() {
             ForEach(items, id: \.self) { item in
+                MyButton(text: item)
             }
         }
     }
 }


これで成功しました

ちなみに、functionをCustom Viewに入れる方法もあります

 struct MyButton: View {
     var text: String
+    var clickEvent: () -> Void
     @State private var animationAmount = 0.0
    
     var body: some View {
         Button(text) {
             withAnimation {
                 animationAmount += 360
             }
+            clickEvent()
         }
         .buttonStyle(.borderedProminent)
         .rotation3DEffect(.degrees(animationAmount), axis: (x: 0, y: 1, z:  0))
     }
}

 struct ContentView: View {
    
     let items = ["Forest", "Sun", "Moon", "Sea"]
     @State private var clickedItem = "No one"

     var body: some View {
        
         VStack() {
             ForEach(items, id: \.self) { item in
+                MyButton(text: item, clickEvent: {
+                     clickedItem = item
+                 })
             }
+            Text("\(clickedItem) is clicked")
         }
     }
 }

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Discussion