I am developing the app for IOS and I am the first time using SwiftUI, just a beginner. The problem is that I try to change the values of Text() by button click that are made by using ForEach Identifiable. Everything is nice but this is the only thing that I cannot do and find an answer for my self on internet.
This is the view of application
Here is my code
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")
]
Big Thanks!
CodePudding user response:
In order for your data array to be mutable, it should be stored in @State in your View. Then, you can pass it via Binding to your child View.
(I've also adjusted the capitalization of your types to fit the Swift conventions, so be careful to reflect that in your code if you 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
}
Update, based on asker's new information:
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
}
Or, an option that stores the ID of the selected item:
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: { $0.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)
}
}
