It may be a bug of SwiftUI? There is a Picker component and two buttons in the ContentView. The first button is simply changing the "show" var to true and the second button change the var with a delay. The sheet should be present by tapping the buttons. But I found that if the Picker is tapped at first and keep nothing selected then only the button with delay can present the sheet. The button without delay will cause an error:
[Presentation] Attempt to present <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x14e80e400> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x14c819600> (from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x14c819600>) which is already presenting <_UIContextMenuActionsOnlyViewController: 0x14d63be90>.
After that, the sheet will never be able to present again. Is that the only solution (adding a delay) to avoid this situation?
import SwiftUI
struct ContentView: View {
@State var show = false
@State var picked = "1"
let values = ["1", "2", "3"]
var body: some View {
VStack {
Picker(selection: $picked, label: Text("")) {
ForEach (values, id: \.self) { value in
Text(value)
}
}
Text("⬆️ Tap me but don't select")
.padding(.bottom, 120)
Text("1. Tap Picker")
Text("2. Tap show sheet button")
Button("show sheet") {
show = false
show = true
}
.padding([.top, .bottom], 20)
Button("show sheet with delay") {
DispatchQueue.main.asyncAfter(deadline: .now() 0.1) {
show = true
}
}
}
.padding()
.sheet(isPresented: $show, content: {
Button("close") {
show = false
}
})
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
CodePudding user response:
The issue you're experiencing is due to a bug in SwiftUI where the Picker component can interfere with the presentation of a sheet. The Picker component is a known to have this issue in some cases.
The solution you've found, adding a delay before showing the sheet, allows the Picker component to finish its internal processing before the sheet is presented, which avoids the conflict.
Another solution would be to dismiss the Picker component before showing the sheet, this can be done using resignKeyboard()
or endEditing(_:)
method on the Picker element.
Also, you can try to wrap the Picker component inside Group
or VStack
or ZStack
a nd see if it works.