Learn how to make SwiftUI respond individually to tap gestures from views arranged using the ForEach syntax.

Asked 2 years ago, Updated 2 years ago, 78 views

Question details
When I tapped the views arranged using the ForEach syntax in SwiftUI, I wanted to move them so that only the tapped views change color, so I first created the following test code:

I have a question,
For the time being, I got the results I expected from this test code, but if the number of views is more than just three (for example, if the test code is one row and three columns, but 20 rows and 30 columns), would the same implementation be acceptable?

I have to prepare as many @State variables as the number of views I have, and I have to ask you because I can't help but think there's a better way.

If you notice anything, please let us know.

sample code

//Xcode Version 12.3 (12C33)
// Swift version Apple Swift version 5.3.2

import SwiftUI

struct ContentView:View {
    
    @State variant = [false, false, false]
    
    varbody:someView {
        HSTack(spacing:20){
            ForEach(0..<3) {in
                Text("\(i)")
                    .frame (width:50, height:50)
                    .font(.custom("default", size:30))
                    .background(self.tapped[i]? Color.blue: Color.red)
                    .onTapGesture{
                        taped[i].toggle()
                    }
            }
        }
    }
}

structureContentView_Previews:PreviewProvider{
    static var previews:someView {
        ContentView()
    }
}

swift swiftui

2022-09-30 19:57

2 Answers

You have to prepare as many @State variables as you have views, and you can't help but think there's a better way to do it

< p > 「 state does not, you will need to manage the state variable number of cells is prepared to say 」 the UI the basics of managing a plurality of cells by Swift.「一つのセルごとに複数の別々の状態がある」と言うのであれば、複数個の配列を管理することは避けて、一つのセルの状態を表すstructを定義するなどした方が良いですが、単に配列の要素が複数あるのを、「もっと良いやり方があるように思えてならない」と言うのは、SwiftUI的発想に慣れていないように思われます。

I've seen @Statevartaped1:Bool=false, @Statevartaped2:Bool=false, @Statevartaped3:Bool=false... in some Q&A site before. Rather, I can say that I've used @Statevartaped.

With a little ingenuity in writing, you won't have to fiddle with the code even if you change the number of elements.

struct ContentView:View {
    
    @State variant = Array (repeating: false, count:5)
    
    varbody:someView {
        HSTack(spacing:20){
            ForEach(tapped.indices) {in
                Text("\(i)")
                    .frame (width:50, height:50)
                    .font(.custom("default", size:30))
                    .background(self.tapped[i]? Color.blue: Color.red)
                    .onTapGesture{
                        taped[i].toggle()
                    }
            }
        }
    }
}

If you want to manage only two states of true/false for all cells, you can use Set, but this is not a good technique to remember because there are few situations where you can use it.

struct ContentView:View {
    
    @State variantIndices: Set<Int>=[ ]
    
    varbody:someView {
        HSTack(spacing:20){
            ForEach(0..<3) {in
                Text("\(i)")
                    .frame (width:50, height:50)
                    .font(.custom("default", size:30))
                    .background(self.tappedIndices.contains(i)?Color.blue:Color.red)
                    .onTapGesture{
                        if tappedIndices.contains(i){
                            taggedIndices.remove(i)
                        } else{
                            taggedIndices.insert(i)
                        }
                    }
            }
        }
    }
}


2022-09-30 19:57

It can also be implemented in the form of having a variable in another View.

struct ContentView:View {
  varbody:someView {
    HSTack(spacing:20){
      ForEach(0..<3) {in
        TappableText(text:String(i))
          .frame (width:50, height:50)
          .font(.custom("default", size:30))
      }
    }
  }
}

structureTappableText:View {
  let text —String

  @State variant=false

  varbody:someView {
    Text(text)
      .background(tapped?) Color.blue: Color.red)
      .onTapGesture{
        taped.toggle()
      }
  }
}


2022-09-30 19:57

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.