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

SwiftUI:程序化切换Sheet Detent时实现内容高度渐变动画

实现SwiftUI Sheet代码切换PresentationDetent时的渐进式高度动画

问题场景

当使用多PresentationDetent的Sheet时,两种操作的高度变化表现不一致:

  • 拖拽Sheet顶部指示器调整时,视图高度会平滑渐进变化
  • 通过代码直接修改selectedDetent绑定值时,视图会瞬间跳转到目标高度

需要实现代码切换Detent时,也能达到和拖拽操作一致的渐进式高度过渡效果。

解决方案

核心思路是放弃直接修改系统预设Detent的绑定值,转而通过自定义Detent+动画过渡高度变量的方式,实现平滑的高度变化:

  1. 用PresentationDetent.custom定义与系统预设高度匹配的自定义档位
  2. 维护动态高度状态变量,通过withAnimation触发平滑过渡
  3. 同步高度变量与Detent的选中状态,保证Sheet行为一致性

修改后的代码示例

struct TestView: View {
    @State private var currentSheetHeight: CGFloat = UIScreen.main.bounds.height * 0.5
    @State private var selectedDetent: PresentationDetent = .medium
    
    // 匹配系统默认的medium和large高度
    private let mediumHeight = UIScreen.main.bounds.height * 0.5
    private let largeHeight = UIScreen.main.bounds.height * 0.9

    var body: some View {
        VStack {}
            .sheet(isPresented: .constant(true)) {
                Button {
                    // 切换目标高度并应用动画
                    withAnimation(.easeInOut(duration: 0.3)) {
                        currentSheetHeight = currentSheetHeight == mediumHeight ? largeHeight : mediumHeight
                    }
                } label: {
                    Text("\(Int(currentSheetHeight))")
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                }
                .padding()
                .buttonStyle(.borderedProminent)
                .presentationDetents([
                    .custom(.init(id: "medium") { _ in self.mediumHeight }),
                    .custom(.init(id: "large") { _ in self.largeHeight })
                ], selection: $selectedDetent)
                .interactiveDismissDisabled()
                // 同步高度变化到Detent选中状态
                .onChange(of: currentSheetHeight) { newHeight in
                    selectedDetent = newHeight == mediumHeight 
                        ? .custom(.init(id: "medium") { _ in self.mediumHeight })
                        : .custom(.init(id: "large") { _ in self.largeHeight })
                }
            }
    }
}

代码说明

  • 定义mediumHeight和largeHeight对齐系统预设档位的高度,保证视觉效果一致
  • 点击按钮时,用withAnimation包裹高度变量的切换,触发UIKit级别的平滑过渡动画
  • 使用自定义PresentationDetent将高度值与Sheet档位绑定,替代系统预设的.medium/.large
  • 通过onChange监听高度变化,同步更新selectedDetent,确保Sheet的交互状态与高度匹配

效果对比

拖拽调整Sheet代码切换Detent(带动画)
拖拽时的渐进动画代码切换时的渐进动画

内容的提问来源于stack exchange,提问作者Benoît

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 07:04:51