I have three level struct view and I couldn't figure out how to pass the image change from 3rd to 1st. I am confused with how to use @State and @Binding in my "iconValue" property. The image on the highest level view only changes after dismiss and reopen the screen.
The highest level view is "ExLibrisStyleView".It includes row categories of icon collection fed from "ExLibrisCategoryRow" view. On top of the view it shows selected icon. "ExLibrisCategoryRow" is combination of images called from "ExLibrisCategoryItem". When I tap on any image I want to change the selected icon on top of the view instantly. However it changes after main view is dismissed and reopened again. Really appreciate to show me where is the mistake which leads to image update after reopen the view.
my code for each struct view is:
ExLibrisStyleView
view
import SwiftUI
struct ExLibrisStyleView: View {
@EnvironmentObject var exlibrisData: ExLibrisModelData
@State var iconValue = UserDefaults.standard.string(forKey: "iconValue")
var body: some View {
NavigationView{
List {
VStack(alignment: .leading) {
Text("Selected Bookmark").font(.headline).padding(.bottom,15)
Image(iconValue ?? "exlibris-0")
.renderingMode(.original)
.resizable()
.frame(width: 130, height: 130)
.cornerRadius(5)
.shadow(color: Color(red:0, green:0, blue:0, opacity:0.25), radius: 8, x: 0, y: 0)
}
.padding(.leading, 15)
.padding(.bottom,30)
.listStyle(.inset)
.listRowInsets(EdgeInsets())
ForEach(exlibrisData.categories.keys.sorted(), id: \.self) { key in
ExLibrisCategoryRow(categoryName: key, items: exlibrisData.categories[key]!,iconValue: iconValue ?? "exlibris-0")
}
.listRowInsets(EdgeInsets())
}
.listStyle(.inset)
.navigationTitle("Bookmark Collection")
}
}
}
ExLibrisCategoryRow
view:
import SwiftUI
struct ExLibrisCategoryRow: View {
var categoryName: String
var items: [ExLibris]
@State var iconValue: String
var body: some View {
VStack(alignment: .leading) {
Text(categoryName)
.font(.headline)
.padding(.leading, 15)
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .top, spacing: 0) {
ForEach(items) { exlibris in
label: do {
ExLibrisCategoryItem(exlibris: exlibris, iconValue: $iconValue)
}
}
}
}
.frame(height: 200)
}
}
}
ExLibrisCategoryItem
View:
import SwiftUI
struct ExLibrisCategoryItem: View {
var exlibris: ExLibris
@Binding var iconValue: String
var body: some View {
VStack(alignment: .leading) {
Image(exlibris.imageName)
.renderingMode(.original)
.resizable()
.frame(width: 130, height: 130)
.cornerRadius(5)
.onTapGesture {
print(iconValue)
UserDefaults.standard.set(exlibris.imageName, forKey: "iconValue")
iconValue = UserDefaults.standard.string(forKey: "iconValue") ?? "exlibris-0"
}
}
.padding(.leading, 15)
}
}
After spending hours how to solve the problem or change the logic behind the views, I have searched the solution in a different way and just found out an elegant wrapper called @AppStorage to update any view with UserDefaults. It is exactly the one I was looking for. I have found out it in this post and other link explains how to use.