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)
}
}