如何使用 ForEach Identifiable SwiftUI 更改按钮按下时的值

How to change value on button press using ForEach Identifiable SwiftUI

我正在为 IOS 开发应用程序,我是第一次使用 SwiftUI,只是一个初学者。 问题是我尝试通过使用 ForEach Identifiable 进行的按钮单击来更改 Text() 的值。一切都很好,但这是我唯一做不到的,只能在网上找到自己的答案。

This is the view of application

这是我的代码


import SwiftUI

private struct SizePreferenceKey: PreferenceKey {
  static var defaultValue: CGSize = .zero
  static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}

public struct SemaphoreFlags: View {
    @State private var headerHeight = CGSize()
    
    public var body: some View {
        ZStack{
            
            Image("background")
                .resizable()
                .scaledToFill()
                .frame(maxWidth: UIScreen.screenWidth, maxHeight: UIScreen.screenHeight )
                .edgesIgnoringSafeArea(.bottom)
            
                VStack{
                    
                    Image("header_inv")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(maxWidth: UIScreen.screenWidth ,alignment: .top)
                        .opacity(0.0)
                        .readSize {
                            height in headerHeight = height
                        }.padding(.bottom, 16)
                    
                    Text("HEADER TEXT")
                        .foregroundColor(.white)
                        .font(.system(size: 24))
                        .fontWeight(.medium)
                        .frame(width: UIScreen.screenWidth - 25, height: UIScreen.screenWidth / 6, alignment: .center)
                        .background(Color(red: 0.29, green: 0.67, blue: 0.88))
                        .padding(.bottom, 4.0)
                    
                    ScrollView{
                        Text(NSLocalizedString("BeaufortScale_Description", comment: "BeaufortScale_Description"))
                            .font(.system(size: 20))
                            .multilineTextAlignment(.center)
                            .background(Color.white)
                            .padding(.horizontal,8)
                            .foregroundColor(.black)
                            .frame(width: .infinity, height: .infinity)
                        
                    }
                    
                    Image("blank")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: UIScreen.screenWidth - 25, height: UIScreen.screenWidth / 2, alignment: .center)
                    
                    
                    Text("BottomLETTER")
                        .font(.system(size: UIScreen.screenWidth/6))
                        .fontWeight(.medium)
                        .multilineTextAlignment(.center)
                        .foregroundColor(Color(red: 0.09, green: 0.30, blue: 0.47))
                        .frame(width: UIScreen.screenWidth, height: .infinity, alignment: .center)
                    
                    Spacer()
                    
                    ScrollView(.horizontal, showsIndicators: false){
                        HStack{
                            ForEach(semaphoreButtonPropsData) { item in
                                semaphoreFlagsButton(SemaphoreButtonProps: item)
                            }
                        }
                    }.clipped().edgesIgnoringSafeArea(.bottom).padding(.vertical)

                }.frame(width: .infinity, height: .infinity)
            
            
            
            Image("header")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(maxWidth: UIScreen.screenWidth, maxHeight: UIScreen.screenHeight ,alignment: .top)
                
            VStack {
                HStack {
                    Button (action: gotoMenu, label: {
                        Image("back")
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: 32, height: headerHeight.height)
                            .padding(.leading, 16.0)
                            
                    })
                    
                    Spacer()
                }
                Spacer()
            }
            
        }.background(Color(red: 0.09, green: 0.30, blue: 0.47).edgesIgnoringSafeArea(.all))
    }
}

struct SemaphoreFlags_Previews: PreviewProvider {
    static var previews: some View {
        SemaphoreFlags()
    }
}

struct semaphoreFlagsButton: View {
    var SemaphoreButtonProps: semaphoreButtonProps
    var body: some View {
        Button(action:{
           // ACTION TO CHANGE THE VALUES OF DESIGN 
                        (HEADER TEXT, DESCRIPTION, IMAGE, BOTTOM LETTER)

        }, label: {
            Text(SemaphoreButtonProps.buttonLetter)
                .font(.system(size: 26))
                .fontWeight(.light)
                .foregroundColor(Color.white)
                .multilineTextAlignment(.leading)
                .padding(.all, 4.0)
                .foregroundColor(.white)
                .frame(width: .infinity, height: 50, alignment: .center)
            
        })
            .frame(width: 100, height: 50 , alignment: .center)
            .background(Color(red: 0.29, green: 0.67, blue: 0.88))
            .cornerRadius(12)
            .padding(.leading, 8)
    }
}

struct semaphoreButtonProps: Identifiable {
    var id = UUID()
    var headerText: String
    var description: String
    var image: Image
    var bottomLetter: String
    var buttonLetter: String
}

let semaphoreButtonPropsData = [
    semaphoreButtonProps(headerText: "About",
                         description: NSLocalizedString("BeaufortScale_Description", comment: "BeaufortScale_Description"),
                         image: Image("blank"),
                         bottomLetter: " ",
                         buttonLetter: "About"),
    
    semaphoreButtonProps(headerText: "Alpha",
                         description: " ",
                         image: Image("a-alpha"),
                         bottomLetter: "A",
                         buttonLetter: "A"),
    
    semaphoreButtonProps(headerText: "Bravo",
                         description: " ",
                         image: Image("b-bravo"),
                         bottomLetter: "B",
                         buttonLetter: "B")
]

非常感谢!

为了使您的数据数组可变,它应该存储在您的 View 中的 @State 中。然后,您可以通过 Binding 将其传递给您的 child View.

(我还调整了您的类型的大小写以适应 Swift 约定,所以如果您 copy/paste 时请小心在代码中反映这一点)

public struct SemaphoreFlags: View {
    @State private var semaphoreButtonPropsData = [ //<-- Here
        SemaphoreButtonProps(headerText: "About",
                             description: NSLocalizedString("BeaufortScale_Description", comment: "BeaufortScale_Description"),
                             image: Image("blank"),
                             bottomLetter: " ",
                             buttonLetter: "About"),
        
        SemaphoreButtonProps(headerText: "Alpha",
                             description: " ",
                             image: Image("a-alpha"),
                             bottomLetter: "A",
                             buttonLetter: "A"),
        
        SemaphoreButtonProps(headerText: "Bravo",
                             description: " ",
                             image: Image("b-bravo"),
                             bottomLetter: "B",
                             buttonLetter: "B")
    ]
    
    public var body: some View {
        ScrollView(.horizontal, showsIndicators: false){
            HStack{
                ForEach($semaphoreButtonPropsData) { $item in //<-- Here
                    SemaphoreFlagsButton(semaphoreButtonProps: $item) //<-- Here
                }
            }
        }
    }
}

struct SemaphoreFlagsButton: View {
    @Binding var semaphoreButtonProps: SemaphoreButtonProps //<-- Here

    var body: some View {
        Button(action:{
            semaphoreButtonProps.buttonLetter = "\(Date())" //<-- Here

        }, label: {
            Text(semaphoreButtonProps.buttonLetter)
        })
            .frame(width: 100, height: 50 , alignment: .center)
            .background(Color(red: 0.29, green: 0.67, blue: 0.88))
            .cornerRadius(12)
            .padding(.leading, 8)
    }
}

struct SemaphoreButtonProps: Identifiable { //<-- Here
    var id = UUID()
    var headerText: String
    var description: String
    var image: Image
    var bottomLetter: String
    var buttonLetter: String
}

根据提问者的新信息更新:

public struct SemaphoreFlags: View {
    @State private var headerText : String = "HEADER TEXT"
    @State private var semaphoreButtonPropsData = [ //<-- Here
        SemaphoreButtonProps(headerText: "About",
                             description: NSLocalizedString("BeaufortScale_Description", comment: "BeaufortScale_Description"),
                             image: Image("blank"),
                             bottomLetter: " ",
                             buttonLetter: "About"),
        
        SemaphoreButtonProps(headerText: "Alpha",
                             description: " ",
                             image: Image("a-alpha"),
                             bottomLetter: "A",
                             buttonLetter: "A"),
        
        SemaphoreButtonProps(headerText: "Bravo",
                             description: " ",
                             image: Image("b-bravo"),
                             bottomLetter: "B",
                             buttonLetter: "B")
    ]
    
    public var body: some View {
        Text(headerText)
        ScrollView(.horizontal, showsIndicators: false){
            HStack{
                ForEach(semaphoreButtonPropsData) { item in //<-- Here
                    SemaphoreFlagsButton(semaphoreButtonProps: item, headerText: $headerText) //<-- Here
                }
            }
        }
    }
}

struct SemaphoreFlagsButton: View {
    var semaphoreButtonProps: SemaphoreButtonProps
    @Binding var headerText : String

    var body: some View {
        Button(action:{
            headerText = semaphoreButtonProps.headerText
        }, label: {
            Text(semaphoreButtonProps.buttonLetter)
        })
            .frame(width: 100, height: 50 , alignment: .center)
            .background(Color(red: 0.29, green: 0.67, blue: 0.88))
            .cornerRadius(12)
            .padding(.leading, 8)
    }
}

struct SemaphoreButtonProps: Identifiable { //<-- Here
    var id = UUID()
    var headerText: String
    var description: String
    var image: Image
    var bottomLetter: String
    var buttonLetter: String
}

或者,存储所选项目 ID 的选项:

public struct SemaphoreFlags: View {
    @State private var selectedSemaphore : UUID? = nil
    @State private var semaphoreButtonPropsData = [ //<-- Here
        SemaphoreButtonProps(headerText: "About",
                             description: NSLocalizedString("BeaufortScale_Description", comment: "BeaufortScale_Description"),
                             image: Image("blank"),
                             bottomLetter: " ",
                             buttonLetter: "About"),
        
        SemaphoreButtonProps(headerText: "Alpha",
                             description: " ",
                             image: Image("a-alpha"),
                             bottomLetter: "A",
                             buttonLetter: "A"),
        
        SemaphoreButtonProps(headerText: "Bravo",
                             description: " ",
                             image: Image("b-bravo"),
                             bottomLetter: "B",
                             buttonLetter: "B")
    ]
    
    public var body: some View {
        if let selected = semaphoreButtonPropsData.first(where: { [=12=].id == selectedSemaphore }) {
            Text(selected.headerText)
        }
        ScrollView(.horizontal, showsIndicators: false){
            HStack{
                ForEach(semaphoreButtonPropsData) { item in //<-- Here
                    SemaphoreFlagsButton(semaphoreButtonProps: item, selectedSemaphore: $selectedSemaphore) //<-- Here
                }
            }
        }
    }
}

struct SemaphoreFlagsButton: View {
    var semaphoreButtonProps: SemaphoreButtonProps
    @Binding var selectedSemaphore : UUID?

    var body: some View {
        Button(action:{
            selectedSemaphore = semaphoreButtonProps.id
        }, label: {
            Text(semaphoreButtonProps.buttonLetter)
        })
            .frame(width: 100, height: 50 , alignment: .center)
            .background(Color(red: 0.29, green: 0.67, blue: 0.88))
            .cornerRadius(12)
            .padding(.leading, 8)
    }
}