I have this code:
import SwiftUI
struct ContentView: View {
@State var show = false
var tools = [Tool("document.on.document"), Tool("document.on.clipboard")]
var body: some View {
HStack{
HStack {
ForEach(tools, id:\.id) { tool in
Button(action: {
print("toggle")
show.toggle()
}, label: {
Image(systemName:tool.name)
.imageScale(.large)
.foregroundStyle(.black.gradient)
.font(.system(size: 30))
})
.contentShape(Rectangle())
.popover(isPresented: $show, arrowEdge: .top) {
Color.red
.frame(width:400, height:400)
.onAppear{
print("popover show")
}
}
}
}
.padding()
}
.background(
RoundedRectangle(cornerSize: CGSize(width: 50,height: 50))
.fill(.red.opacity(0.5).gradient))
.padding()
}
}
#Preview {
ContentView()
}
struct Tool: Identifiable, Equatable {
let id = UUID()
let name:String
init(_ name: String) {
self.name = name
}
}
the popover does not show. I did everything.
Why is that?
You are using a single show
state to control all of the popovers! Multiple popovers cannot be shown at the same time, so noting gets shown.
It is technically possible to change the type of show
to [Bool]
and pass $show[0]
, $show[1]
etc to isPresented
, but it would be quite inconvenient to find the index of the tool
and things like that.
If the parent view doesn't need to know exactly which popovers are shown, you should extract the button into a separate view, and put the show
state there.
struct ToolButton: View {
// move the @State here
@State private var show = false
let tool: Tool
// pass anything else you need here...
var body: some View {
Button(action: {
print("toggle")
show.toggle()
}, label: {
Image(systemName: tool.name)
.imageScale(.large)
.foregroundStyle(.black.gradient)
.font(.system(size: 30))
})
.contentShape(Rectangle())
.popover(isPresented: $show, arrowEdge: .top) {
Color.red
.frame(width:400, height:400)
.presentationCompactAdaptation(.popover) // if you also want a popover on iPhones
.onAppear{
print("popover show")
}
}
}
}
Since the @State
is in ToolButton
, there will be as many states as there are ToolButton
, which means one state to control each popover.
ForEach(tools) { tool in
ToolButton(tool: tool)
}