我在SwiftUI中编写了一个非常简单的.modal
View
修饰符。
当它打开时,我按close
,然后在转换再次完成open
之前,出现以下崩溃:
Gesture: Failed to receive system gesture state notification before next touch
示例代码:
import SwiftUI
struct ContentView: View {
@State var show = false
var body: some View {
VStack {
Button("Open") {
withAnimation {
self.show.toggle()
}
}.disabled(self.show) // doesn't help
}.modal(isShowing: self.$show) {
Button("Close") {
withAnimation {
self.show.toggle()
}
}
}
}
}
extension View {
func modal<C>(isShowing: Binding<Bool>, @ViewBuilder content: @escaping () -> C) -> some View where C: View {
self.modifier(ModalView(isShowing: isShowing, content: content))
}
}
struct ModalView<C>: ViewModifier where C: View {
@Binding var isShowing: Bool
let content: () -> C
func body(content: Content) -> some View {
ZStack {
content.zIndex(0)
if self.isShowing {
self.content()
.background(Color.primary.colorInvert())
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.transition(.move(edge: .bottom))
.zIndex(1)
}
}
}
}
有人可以解释我如何防止这种情况发生吗?似乎负责切换的Bool
是在动画完成之前设置的。这是设计使然吗?
答案 0 :(得分:1)
是的,您需要禁用下面的内容(在介绍模态时),但要在其他地方有所不同
此处是固定变体。经过Xcode 12 / iOS 14的测试
struct ModalView<C>: ViewModifier where C: View {
@Binding var isShowing: Bool
let content: () -> C
@State private var interactive: Bool // track state
init(isShowing: Binding<Bool>, @ViewBuilder content: @escaping () -> C) {
self._isShowing = isShowing
self._interactive = State(initialValue: !isShowing.wrappedValue)
self.content = content
}
func body(content: Content) -> some View {
ZStack {
content.zIndex(0).disabled(!interactive) // disable here !!
if self.isShowing {
self.content()
.background(Color.primary.colorInvert())
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.transition(.move(edge: .bottom))
.zIndex(1)
.onAppear { self.interactive = false } // << !!
.onDisappear { self.interactive = true } // << !!
}
}
}
}