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

iOS 16.4中SwiftUI拖拽Sheet时能否实时获取其高度?

iOS 16.4中获取Sheet拖拽实时高度及实现动画的方法

在iOS 16.4中,官方并没有直接提供API来获取Sheet拖拽过程中的实时高度,但可以通过结合UIKit的底层交互能力,间接实现这一需求,并且能基于实时高度值完成相关动画效果。

获取实时拖拽高度

核心思路是借助UISheetPresentationController(SwiftUI Sheet的底层实现),通过监听其容器视图的状态变化来获取实时高度:

  1. 在Sheet的内容视图中,通过UIViewControllerRepresentable桥接到UIKit,获取对应的UISheetPresentationController实例。
  2. 监听Sheet容器视图的frame变化,计算出当前Sheet的实时高度。
  3. 将计算结果传递回SwiftUI的状态变量,供视图逻辑使用。

示例代码如下:

import SwiftUI

// 用于监听Sheet实时高度的UIKit桥接视图
struct SheetHeightMonitor: UIViewControllerRepresentable {
    @Binding var currentHeight: CGFloat
    
    func makeUIViewController(context: Context) -> UIViewController {
        let vc = UIViewController()
        vc.view.backgroundColor = .clear
        return vc
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        guard let sheetController = uiViewController.parent?.sheetPresentationController else { return }
        
        // 监听容器视图frame变化
        context.coordinator.observer = NSKeyValueObservation.observe(
            sheetController.containerView!,
            keyPath: \.frame,
            options: [.new]
        ) { [weak self] _, change in
            guard let newFrame = change.newValue else { return }
            // 计算实时高度:屏幕总高度减去容器视图的顶部偏移
            self?.currentHeight = UIScreen.main.bounds.height - newFrame.minY
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator {
        var observer: NSKeyValueObservation?
    }
}

// 使用示例
struct ContentView: View {
    @State var isSheetPresented = false
    @State var detent: PresentationDetent = .height(200)
    @State var sheetRealTimeHeight: CGFloat = 200 // 存储实时高度
    
    var body: some View {
        Button("打开Sheet") {
            isSheetPresented = true
        }
        .sheet(isPresented: $isSheetPresented) {
            VStack {
                Text("当前Sheet高度:\(sheetRealTimeHeight, specifier: "%.1f")")
                Spacer()
            }
            .padding()
            .background(Color.white)
            // 添加高度监听视图
            .background(SheetHeightMonitor(currentHeight: $sheetRealTimeHeight))
        }
        .presentationDetents([.height(200), .height(500)], selection: $detent)
    }
}

基于实时高度实现动画

拿到实时高度值后,可直接在SwiftUI视图中基于该值驱动动画效果,比如根据高度变化调整视图的缩放比例、透明度或位置:

// 在Sheet内容视图中添加动画效果
VStack {
    Text("拖拽我试试")
        .font(.title)
        // 高度从200到500时,缩放比例从0.8过渡到1.0
        .scaleEffect(sheetRealTimeHeight / 500 * 0.2 + 0.8)
        .animation(.easeInOut(duration: 0.1), value: sheetRealTimeHeight)
    
    Circle()
        .fill(Color.blue)
        .frame(width: 80, height: 80)
        // 高度越高,透明度越高
        .opacity(sheetRealTimeHeight / 500)
        .animation(.easeInOut(duration: 0.1), value: sheetRealTimeHeight)
    
    Spacer()
}

需要注意的是,frame变化的回调会比较频繁,若有性能顾虑可添加节流处理,避免不必要的视图刷新。

内容的提问来源于stack exchange,提问作者Nicolas Gimelli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 21:45:18