SheetKit 是 SwiftUI Sheet 的扩展库。
SheetKit 是 SwiftUI 模态视图的扩展库。它为模态视图提供了一些方便的显示和取消方法,以及一些用于模态视图的 View Extension。
开发 SheetKit 的主要原因。
便捷的 Deep Link 调用 SwiftUI 提供了 onOpenURL 方法,使应用程序可以非常容易地响应 Deep Link,但实际上,这并不像预期的那么容易。 主要原因是 SwiftUI 中重要的视图呈现模式:NavigationView、Sheet 等,不具备快速简便地重置的能力。 很难通过几行代码立即将应用程序设置为我们想要的视图状态。
模态视图的集中管理 SwiftUI 通常使用 .sheets 来创建模态视图,这对于简单的应用程序来说非常直观,但如果应用程序逻辑复杂且需要许多模态视图,这可能会使代码变得非常混乱且难以组织。 在这种情况下,我们通常集中管理所有模态视图并将它们一起调用。 请参阅我之前的文章 - 在 SwiftUI 中按需弹出不同的 Sheets。
新的 UISheetPresentationController 在 WWDC 2021 中,Apple 为大家带来了期待已久的半高模态视图。 SheetKit 现在弥补了这一点,但也许有点仓促,因为没有这个流行的交互的 SwiftUI 版本,只有 UIKit 支持。 Sheet、fullScreenCover 和 bottomSheet(半高模态视图)都在一个地方得到完全支持和管理。
iOS 15
Swift 5.5
XCode 13.0 +
Button("show sheet"){
SheetKit().present{
Text("Hello world")
}
}
或
@Environment(\.sheetKit) var sheetKit
Button("show sheet"){
sheetKit.present{
Text("Hello world")
}
}
支持 multiSheet (多 Sheet)
@Environment(\.sheetKit) var sheetKit
Button("show sheet"){
sheetKit.present{
Button("show full sheet"){
sheetKit.present(with:.fullScreenCover){
Text("Hello world")
}
}
}
}
三种类型的样式
sheetKit.present(with: .bottomSheet){
Text("Hello world")
}
custom bottomSheet (自定义底部 Sheet)
let configuration = SheetKit.BottomSheetConfiguration( detents: [.medium(),.large()],
largestUndimmedDetentIdentifier: .medium,
prefersGrabberVisible: true,
prefersScrollingExpandsWhenScrolledToEdge: false,
prefersEdgeAttachedInCompactHeight: false,
widthFollowsPreferredContentSizeWhenEdgeAttached: true,
preferredCornerRadius: 100)
sheetKit.present(with: .customBottomSheet,configuration: configuration) {
Text("Hello world")
}
get notice when bottomSheet modal changed (当底部 Sheet 模态发生改变时收到通知)
@State var detent:UISheetPresentationController.Detent.Identifier = .medium
Button("Show"){
sheetKit.present(with: .bottomSheet,detentIdentifier: $detent){
Text("Hello worl")
}
}
.onChange(of: detent){ value in
print(value)
}
或
@State var publisher = NotificationCenter.default.publisher(for: .bottomSheetDetentIdentifierDidChanged, object: nil)
.onReceive(publisher){ notification in
guard let obj = notification.object else {return}
print(obj)
}
SheetKit().dismissAllSheets(animated: false, completion: {
print("sheet has dismiss")
})
SheetKit().dismiss()
SwiftUI 3.0 的 interactiveDismissDisabled 增强功能增加了在用户使用手势取消时收到通知的能力,并且可以通过代码控制是否允许手势取消。
struct ContentView: View {
@State var sheet = false
var body: some View {
VStack {
Button("show sheet") {
sheet.toggle()
}
}
.sheet(isPresented: $sheet) {
SheetView()
}
}
}
struct SheetView: View {
@State var disable = false
@State var attempToDismiss = UUID()
var body: some View {
VStack {
Button("disable: \(disable ? "true" : "false")") {
disable.toggle()
}
.interactiveDismissDisabled(disable, attempToDismiss: $attempToDismiss)
}
.onChange(of: attempToDismiss) { _ in
print("try to dismiss sheet")
}
}
}
将模态视图的背景设置为透明。 在 SwiftUI 3.0 中,已经可以使用原生 API 生成各种毛玻璃效果。 但是,只有将模态视图的背景设置为透明时,才能看到毛玻璃效果。
ZStack {
Rectangle().fill(LinearGradient(colors: [.red, .green, .pink, .blue, .yellow, .cyan, .gray], startPoint: .topLeading, endPoint: .bottomTrailing))
Button("Show bottomSheet") {
sheetKit.present(with: .bottomSheet, afterPresent: { print("presented") }, onDisappear: { print("disappear") }, detentIdentifier: $detent) {
ZStack {
Rectangle()
.fill(.ultraThinMaterial)
VStack {
Text("Hello world")
Button("dismiss all") {
SheetKit().dismissAllSheets(animated: true, completion: {
print("sheet has dismiss")
})
}
}
}
.clearBackground()
.ignoresSafeArea()
}
}
.foregroundColor(.white)
.buttonStyle(.bordered)
.controlSize(.large)
.tint(.green)
}
.ignoresSafeArea()