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

SwiftUI:如何消除Sheet关闭时的延迟?

解决Sheet关闭时视图偏移恢复延迟的问题

问题原因

你遇到的延迟是因为SwiftUI的sheet绑定的isPresented状态,会在Sheet的关闭动画完全结束后才更新为false。这就导致视图偏移的动画要等到Sheet完全消失后才开始,视觉上产生了延迟。

解决方案1:iOS 16.4+ 用PresentationPhase同步动画

iOS 16.4及以上提供了PresentationPhase枚举,它会在Sheet开始呈现/关闭时就更新状态(而非等待动画结束),可以完美同步偏移动画和Sheet的过渡动画:

import SwiftUI

struct FirstView: View {
    // 使用PresentationPhase替代Bool状态
    @State private var presentationPhase: PresentationPhase = .dismissed
    
    var body: some View {
        Text("Hello, World!")
            .onTapGesture {
                presentationPhase = .presenting
            }
            .sheet(isPresented: $presentationPhase.isPresented) {
                LaggyView()
                    .presentationDetents([.medium, .large])
            }
            // 当Sheet处于呈现中或已呈现状态时,保持偏移
            .offset(y: presentationPhase == .presenting || presentationPhase == .presented ? -300 : 0)
            // 绑定动画到PresentationPhase的变化
            .animation(.default, value: presentationPhase)
    }
}

struct LaggyView: View {
    var body: some View {
        Text("hello")
    }
}

解决方案2:兼容旧版本的UIKit代理监听

如果需要支持iOS 16.4以下版本,可以通过UIKit的UIPresentationControllerDelegate监听Sheet开始关闭的事件,提前触发偏移恢复动画:

import SwiftUI
import UIKit

// 监听Sheet关闭开始的协调器
class SheetDismissalCoordinator: NSObject, UIAdaptivePresentationControllerDelegate {
    private let onDismissStarted: () -> Void
    
    init(onDismissStarted: @escaping () -> Void) {
        self.onDismissStarted = onDismissStarted
    }
    
    // Sheet开始关闭时触发
    func presentationControllerWillDismiss(_ presentationController: UIPresentationController) {
        onDismissStarted()
    }
}

// UIViewControllerRepresentable用于注入代理
struct SheetDismissalListener: UIViewControllerRepresentable {
    let onDismissStarted: () -> Void
    
    func makeUIViewController(context: Context) -> UIViewController {
        let vc = UIViewController()
        vc.presentationController?.delegate = context.coordinator
        return vc
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
    
    func makeCoordinator() -> SheetDismissalCoordinator {
        SheetDismissalCoordinator(onDismissStarted: onDismissStarted)
    }
}

struct FirstView: View {
    @State var showSheet: Bool = false
    @State var offsetY: CGFloat = 0
    
    var body: some View {
        Text("Hello, World!")
            .onTapGesture {
                // 弹出Sheet时同步触发偏移动画
                withAnimation(.default) {
                    offsetY = -300
                    showSheet = true
                }
            }
            .sheet(isPresented: $showSheet, onDismiss: {
                // 确保Sheet完全关闭后偏移归位(防止拖拽中断动画)
                offsetY = 0
            }) {
                LaggyView()
                    .presentationDetents([.medium, .large])
                    // 注入监听视图,监听Sheet关闭开始事件
                    .background(SheetDismissalListener {
                        withAnimation(.default) {
                            offsetY = 0
                        }
                    })
            }
            .offset(y: offsetY)
    }
}

struct LaggyView: View {
    var body: some View {
        Text("hello")
    }
}

两种方案都能让视图偏移的动画和Sheet的过渡动画同步进行,彻底消除关闭时的延迟。

内容的提问来源于stack exchange,提问作者b.joe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 04:15:25