SwiftUI BottomSheet关闭白屏及UIKit _endOcclusion失衡警告问题
SwiftUI BottomSheet 关闭白屏与「Unbalanced call to _endOcclusion」问题修复
问题本质
.onDisappear 会在BottomSheet的转场动画尚未完成时就触发,此时直接将 isShowingBottomSheet 设为false,会打乱UIKit内部的视图遮挡管理逻辑,进而引发白屏和警告。而按钮关闭是主动触发状态修改,SwiftUI能同步协调动画与视图状态,因此行为正常。
解决办法
1. 延迟修改状态,等待动画结束
不要在 .onDisappear 中直接修改状态,通过延迟执行让转场动画完成后再更新状态:
ItemInfoView() .onDisappear { DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { isShowingBottomSheet = false } }
0.2秒适配常规BottomSheet动画时长,若你的动画节奏更慢,可适当调整延迟时间。
2. 利用BottomSheet内置关闭回调(UIKit封装场景)
如果你的BottomSheet是基于 UISheetPresentationController 封装的,直接使用其 didDismiss 回调修改状态,替代SwiftUI的 .onDisappear:
// 假设BottomSheet封装提供了didDismiss闭包 ItemInfoView(didDismiss: { isShowingBottomSheet = false })
3. 统一由父视图管理关闭逻辑
让ItemInfoView仅负责发送关闭通知,状态修改交给父视图(LocationRequestIsOnView)处理,避免嵌套层级的状态反向修改冲突:
// ItemInfoView定义 struct ItemInfoView: View { let onClose: () -> Void var body: some View { // 关闭按钮仍调用onClose Button(action: onClose) { Image(systemName: "xmark.circle") } // 将.onDisappear中的状态修改替换为调用onClose .onDisappear { onClose() } } } // 父视图中调用 ItemInfoView(onClose: { withAnimation { isShowingBottomSheet = false } })
4. 用withAnimation包裹状态修改
将状态修改代码放入 withAnimation 中,确保SwiftUI动画系统能正确协调视图变化:
.onDisappear { withAnimation { isShowingBottomSheet = false } }
若该方法无法解决问题,优先采用延迟方案——毕竟触发时机冲突才是问题根源。
内容的提问来源于stack exchange,提问作者Emre Değirmenci
相关产品推荐
相关产品推荐

