You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 02:01:16