First popover showing outdated state

Viewed 181

I've found a to-my-taste weird behavior of popover. I want it to show a view with PopoverItem and number, both are to be set from onTapGesture in ForEach. The issue is that popover always shows the default number on first click, it works as expected for every other.

Wrong (left) and right behavior (on second click works as expected). Same on iOS, same with Button

Text Text

I was able to make it work with Binding but I'd like to find a better solution for presenting popovers and find out why it doesn't work as I expected.

My main view looks like this:

struct PopoverTest: View {
    let array: [PopoverItem] = [PopoverItem("First title"), PopoverItem("second title"), PopoverItem("third title")]
    @State var show: PopoverItem? = nil
    @State var number: Int = 0
    var body: some View {
        VStack {
            ForEach(Array(array.enumerated()), id: \.element.id) { number, item in
                MyPopover(number: number + 1, item: item)
                    .onTapGesture {
                        self.number = number + 1
                        self.show = item
                    }
            }
        }
        .popover(item: $show) { item in
            MyPopover(number: number, item: item)
        }
    }
}

and the popover and item:

struct MyPopover: View {
    let number: Int
    let item: PopoverItem
    var body: some View {
        HStack {
            Text("\(number)")
            Text(item.text)
        }.padding()
    }
}

struct PopoverItem: Identifiable {
    let id = UUID()
    let text: String
    
    init(_ text: String) { self.text = text }
}
1 Answers

The information inside popover passed only via item, ie in

.popover(item: $show) { item in
    MyPopover(number: number, item: item) // << number in only at init !!
}

so this case is invalid for popover

.onTapGesture {
    self.number = number + 1 // << changed only in state !!
    self.show = item        // passed in popover
}

so if you need number in MyPopover, you have to pass it via item by introducing new property in PopoverItem for it.

Related