简体   繁体   中英

SwiftUI onTapGesture interact with caller only

I've just started looking into SwiftUI and since it's so different I'm trying to wrap my head around basic concepts.

In this scenario, how would I go about changing the color only for the circle tapped?

ForEach(1...count, id: \.self) { _ in
    Circle()
        .foregroundColor(colors.randomElement()).opacity(0.2)
        .frame(width: .random(in: 10...100), height: .random(in: 10...100))
        .position(x: .random(in: self.stepperValue...400),
                  y: .random(in: self.stepperValue...400))
        .saturation(2.0)
        .onTapGesture(count: 1, perform: {
            // Change color of circle that was tapped
            print("Tapped")
        })
        .animation(.default) // Animate the change in position

}

Well there are two main options I see here

  1. Make a custom view like
struct MyCircle: View {

    @State var color: Color?

    var body: some View {
        Circle()
            .foregroundColor(color)
            .onTapGesture {
                self.color = colors.randomElement()
            }
    }
}

and then integrate that or

  1. Use a model for your color
struct MyView: View {
    
    @State var colors = allColors.indices.compactMap { _ in allColors.randomElement() }
    
    var body: some View {
        ForEach(colors.indices) { index in
            Circle()
                .foregroundColor(colors[index])
                .onTapGesture {
                    colors[index] = allColors.randomElement()
                }
        }
    }
}

A state like this should preferably be in its own class which should be inserted as ObservedObject .

You create a View that has the "Rows" individual properties

import SwiftUI
struct SampleColorChangeView: View {
    //If the options are fixed no need to keep an eye on them
    //You can move this down to the Row if you don't need to have them available here
    let colors: [Color] = [.red,.blue,.gray, .yellow,.orange]
    @State var count: Int = 10
    var body: some View {
        VStack{
            ForEach(1...count, id: \.self) { _ in
                RowView(colors: colors)
                
            }
        }
    }
}
//Create a row View to observe individual objects
//You will do this with anything that you want to Observe independently
struct RowView: View {
    let colors: [Color]
    //@State observes changes so the View is updated
    @State var color: Color = .blue
    //This kind of works like the colors do you want one for each or a shared for all. Does the parent need access? You can move it up or keep it here
    @State var stepperValue: CGFloat = 0
    //The only change here is the reference to the individual Color
    var body: some View {
        Circle()
            //You set the individual color here
            .foregroundColor(color).opacity(0.2)
            .frame(width: .random(in: 10...100), height: .random(in: 10...100))
            .position(x: .random(in: self.stepperValue...400),
                      y: .random(in: self.stepperValue...400))
            .saturation(2.0)
            .onTapGesture(count: 1, perform: {
                // Change color of circle that was tapped
                color = colors.randomElement()!
                print("Tapped")
            })
            .animation(.default) // Animate the change in position
            //If you want to set a random color to start vs just having them all be the same Color you can do something like this
            .onAppear(){
                color = colors.randomElement()!
            }
    }
}
struct SampleColorChangeView_Previews: PreviewProvider {
    static var previews: some View {
        SampleColorChangeView()
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM