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

SwiftUI/UIKit实现底部Sheet非Large档位回落效果的方法

实现底部Sheet非Large档位的回落效果(SwiftUI & UIKit)

SwiftUI 实现方案

原生SwiftUI的Sheet默认仅.large档位支持拖拽回落,要在其他档位实现该效果,需借助UIKit的UISheetPresentationController代理自定义 dismissal 逻辑:

  1. 创建代理类处理回落逻辑
class SheetDelegate: NSObject, UISheetPresentationControllerDelegate {
    func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
        guard let sheetController = presentationController as? UISheetPresentationController else { return }
        guard let currentDetent = sheetController.selectedDetentIdentifier else { return }
        
        // 非large档位时触发回落,这里以回落至medium为例
        if currentDetent != .large {
            sheetController.animateChanges {
                sheetController.selectedDetentIdentifier = .medium
            }
        } else {
            // large档位正常关闭Sheet
            presentationController.presentingViewController.dismiss(animated: true)
        }
    }
}
  1. 在SwiftUI视图中注入代理
struct SheetProxy: UIViewControllerRepresentable {
    let delegate: SheetDelegate
    
    func makeUIViewController(context: Context) -> UIViewController {
        let vc = UIViewController()
        vc.modalPresentationStyle = .pageSheet
        vc.sheetPresentationController?.delegate = delegate
        return vc
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}

struct ContentView: View {
    @State private var showing = false
    private let sheetDelegate = SheetDelegate()
    
    var body: some View {
        Button("Toggle") {
            showing.toggle()
        }
        .sheet(isPresented: $showing) {
            Text("Test sheet")
                .presentationDetents([.medium, .large])
                .background(SheetProxy(delegate: sheetDelegate))
        }
    }
}

UIKit 实现方案

直接基于UISheetPresentationController配置档位并实现代理:

class ViewController: UIViewController {
    private let sheetDelegate = SheetDelegate()
    
    @IBAction func toggleSheet(_ sender: UIButton) {
        let sheetVC = UIViewController()
        sheetVC.view.backgroundColor = .systemBackground
        sheetVC.modalPresentationStyle = .pageSheet
        
        if let sheetController = sheetVC.sheetPresentationController {
            sheetController.detents = [.medium(), .large()]
            sheetController.delegate = sheetDelegate
        }
        
        present(sheetVC, animated: true)
    }
}

// 复用之前的SheetDelegate类
class SheetDelegate: NSObject, UISheetPresentationControllerDelegate {
    func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
        guard let sheetController = presentationController as? UISheetPresentationController else { return }
        guard let currentDetent = sheetController.selectedDetentIdentifier else { return }
        
        if currentDetent != .large {
            sheetController.animateChanges {
                sheetController.selectedDetentIdentifier = .medium
            }
        } else {
            presentationController.presentingViewController.dismiss(animated: true)
        }
    }
}

补充说明

  • 若需自定义档位(如固定高度的Sheet),可使用UISheetPresentationController.Detent.custom()创建,在代理中匹配对应identifier即可调整回落目标。
  • 回落动画通过系统animateChanges方法触发,与原生Sheet动画保持一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 11:15:56