0
votes

My UIView needs to have an object pass to it before it can show as an active sheet. The object pass into it depends on the button that the user has clicked. That's why i wrote some code like this.

struct DetailInfoView: View {
    
    var cat: Cat

@EnvironmentObject var modelData: ModelData
@State var activeSheet: DetailViewActiveSheet?

@State var selectedFood: Food?

var body: some View {
   ZStack {
   ForEach(foods, id:\.self) {food in
                                    Button(action: {
                                        selectedFood = food
                                        activeSheet = .foodDetailView
                                    }, label: {
                                        Text(food.name).font(.caption2).padding(.top, -5.0)                                             
                                        })
                                    }
    }
    }.sheet(item: $activeSheet) { item in
        switch item {
        case .foodDetailView:
            FoodDetailView(food: self.selectedFood!)
        }
    }
}

I then find that even I have set selectedFood in the button action, it is forever nil and cause exception. Why it is the case?

FoodDetailView has nothing special.

struct FoodDetailView: View {

 var food: Food

  var body: some View {
     Text(food.name)
  }
}

I have another view that will show all my FoodDetailView. Whenever I change the var food to @binding var food of my FoodDetailView, it complains.

TabView() {
        ForEach(modelData.foods) { food in
            FoodDetailView(food: food)
        }
    }.tabViewStyle(PageTabViewStyle())

Maybe to clarify my question --- it should be:

  1. I have multiple active sheets. That's why the .sheet will receive the item $activeSheet so that I know which other view should be shown.
  2. For each of the View to be shown, they may need custom items. The items can only be created when the user click on the button. However, it appears that the .sheet and the related codes are created when the view is created, hence caused the exception. There are suggestion telling that I should use @binding here.
  3. If I use @binding to the variable selectedFood, then may I know how to create the FoodDetailView() if I do not have any binding food variables in other views? For example, I have a list of Food Items, and I use a for loop just loop and create the FoodDetailView. In this case, when I loop the Food Item list, it is not a binding variable.

So I think my question is --- How to make those View created in .sheet() can be created on the fly?

2
Your item should be self.selectedFood, ie. model, not the view.Asperi
Can you please share DetailViewActiveSheet model?Hardik Shekhat
enum DetailViewActiveSheet: Identifiable { case FoodView case AudioView var id:Int { hashValue } }user6539552

2 Answers

0
votes

The item is what transferred into sheet block, so your design should be aligned to

}.sheet(item: $selectedFood) { item in
    switch item {
    case .foodDetailView:
        FoodDetailView(food: item)
    }
}

in this case item contains selectedFood once it has set.

0
votes

Can you share your View: FoodDetailView ? FoodDetailView(food: self.selectedFood!) is initiated when DetailInfoView appear.

I think you can edit like this :

struct DetailInfoView: View {

var cat: Cat

@EnvironmentObject var modelData: ModelData
@State var activeSheet: DetailViewActiveSheet?

@State var selectedFood: Food = Food() //just init even as empty

var body: some View {
   ZStack {
    ForEach(foods, id:\.self) {food in
       Button(action: {
          selectedFood = food
          activeSheet = .foodDetailView
       }, label: {                   
          Text(food.name).font(.caption2).padding(.top, -5.0)                                             
       })
       }
    }
}.sheet(item: $activeSheet) { item in
    switch item {
    case .foodDetailView:
        FoodDetailView(food: self.selectedFood)
    }
}
}

And remove @Binding I put earlier in FoodDetailView