Reputation: 3828
I am attempting to create an 'expandable menu'.
So far I have created a 'menuArray' which contains a list of the headings and also an array of sub headings.
struct menuStruct: Identifiable {
var id: Int
var text: String
var isExpanded: Bool
var subItems: [subMenuStruct]?
}
struct subMenuStruct {
var text: String
var selected: Bool
var link: pagesEnum
}
When the user taps the row, I am toggling the menuArray.isExpanded value.
The issue I have is that when the row is tapped, the UI is not being updated. The print statement shows that the array has been correctly changed but for what ever reason its not being reflected in the list.
Initially I was holding the array as a 'State' object but read that the changing of a value within an element is not considered a change, therefore I should use an observable object. This doesn't seem to have helped.
Why aren't the changes the the array values being reflected in the UI?
thanks!
class MenuViewModel: ObservableObject {
@Published var menuArray: [menuStruct] = [menuStruct(id: 1, text: "SMS", isExpanded: false, subItems: [subMenuStruct(text: "Stats", selected: false, link: .smsStats),subMenuStruct(text: "Customers", selected: false, link: .smsCustomers),subMenuStruct(text: "Activity", selected: false, link: .smsActivity),subMenuStruct(text: "Customer Care", selected: false, link: .smsCutomerCare),subMenuStruct(text: "Keywords", selected: false, link: .smsKeywords)]),menuStruct(id: 2, text: "Online Chat", isExpanded: false, subItems: [subMenuStruct(text: "Stats", selected: false, link: .ocStats),subMenuStruct(text: "Customers", selected: false, link: .ocCustomers),subMenuStruct(text: "Activity", selected: false, link: .ocActivity)]),menuStruct(id: 3, text: "Console", isExpanded: true, subItems: [subMenuStruct(text: "Queues", selected: false, link: .queues)]),menuStruct(id: 4, text: "Support", isExpanded: false, subItems: [subMenuStruct(text: "Contact Admin", selected: false, link: .support)])]
}
struct Menu: View {
@ObservedObject var menuVM = MenuViewModel()
@EnvironmentObject var settings: UserSettings
var body: some View {
GeometryReader { geo in
VStack(spacing: 0){
Spacer().frame(height: geo.safeAreaInsets.top)
HStack(spacing:0){
Text("AllStar.").font(.custom("Poppins-Bold", size: 39))
Spacer()
Image("Cross").resizable().frame(width:20, height: 20).onTapGesture {
self.settings.menuShowing = false
}
}.padding(.horizontal,20)
HStack(spacing:0){
Text("Chat").font(.custom("Poppins-Bold", size: 39)).foregroundColor(Color.init("Pink"))
Spacer()
}.padding(.leading,20)
ScrollView{
HStack{
Text("Dashboard").font(.custom("Poppins-Bold", size: 24))
Spacer()
}.padding(.top,10).padding(.horizontal,20)
ForEach (self.menuVM.menuArray.indices){ index in
HStack(spacing:0){
Text(self.menuVM.menuArray[index].text).font(.custom("Poppins-Bold", size: 24))
if(self.menuVM.menuArray[index].subItems != nil){
Image("downArrow").resizable().frame(width:40,height:15)
}
Spacer()
}.onTapGesture {
// Tapping the row will cause it to expand
self.menuVM.menuArray[index].isExpanded.toggle()
self.menuVM.objectWillChange.send()
print(String.init(describing: self.menuVM.menuArray))
}
if self.menuVM.menuArray[index].isExpanded {
Text("Expanded!")
}
}.padding(.horizontal,20)
}
Spacer()
}.background(Color.white).edgesIgnoringSafeArea(.all)
}
}
}
Upvotes: 1
Views: 594
Reputation: 36274
This is what I did to make things work. Change the structs to classes, because you have to change the values in them, and structs do not allow that. This is one of the reasons why the view is not updating.
class menuStruct: Identifiable {
var id: Int
var text: String
var isExpanded: Bool
var subItems: [subMenuStruct]?
init(id: Int, text: String, isExpanded: Bool, subItems: [subMenuStruct]?) {
self.id = id
self.text = text
self.isExpanded = isExpanded
self.subItems = subItems
}
}
class subMenuStruct {
var text: String
var selected: Bool
var link: pagesEnum
init(text: String, selected: Bool, link: pagesEnum) {
self.text = text
self.selected = selected
self.link = link
}
}
I also change the ScrollView to:
ScrollView{
HStack{
Text("Dashboard").font(.custom("Poppins-Bold", size: 24))
Spacer()
}.padding(.top,10).padding(.horizontal,20)
ForEach (self.menuVM.menuArray){ menu in
HStack(spacing:0){
Text(menu.text).font(.custom("Poppins-Bold", size: 24))
if(menu.subItems != nil){
Image("downArrow").resizable().frame(width:40,height:15)
}
Spacer()
}.onTapGesture {
// Tapping the row will cause it to expand
menu.isExpanded.toggle()
self.menuVM.objectWillChange.send()
print(String.init(describing: self.menuVM.menuArray))
}
if menu.isExpanded {
Text(" \(menu.text) is Expanded")
}
}.padding(.horizontal,20)
}
Upvotes: 3