使用 SheeKit 在 SwiftUI 中自定义和调整 sheet 的大小。利用 UISheetPresentationController
和其他 UIKit 功能的强大功能。
SheeKit 是 SwiftUI 和 UIKit 之间的桥梁,它使用 UIKit 中可用的功能来丰富 SwiftUI 中的模态演示。
SheeKit 提供了两个用于呈现 sheet 的修饰符,类似于 SwiftUI.sheet(...)
isPresented
布尔标志控制Identifiable
项目控制此外,SheeKit 允许
detents
以呈现半屏 sheetIdentifiable
项目定义不同的模态演示样式UIViewControllerProxy
自定义首选的呈现视图控制器属性UIPopoverPresentationController.adaptiveSheetPresentationController
并自定义 popover 的自适应 sheet,该 sheet 将在 iPhone 上以及 iPad 场景的紧凑水平尺寸类中使用。在 iOS 15 中,sheets 可以在 large()
和 medium()
detents 之间调整大小,并动画显示大小转换。 为了自定义 detents,请将 SheetProperties
提供给 ModalPresentationStyle/pageSheet(properties:)
或 ModalPresentationStyle/formSheet(properties:)
。
struct ShowLicenseAgreement: View {
@State private var isShowingSheet = false
@State private var selectedDetentIdentifier = UISheetPresentationController.Detent.Identifier.medium
var body: some View {
Button(action: {
isShowingSheet.toggle()
}) {
Text("Show License Agreement")
}
.shee(isPresented: $isShowingSheet,
presentationStyle: .formSheet(properties: .init(detents: [ .medium(), .large() ], selectedDetentIdentifier: $selectedDetentIdentifier, animatesSelectedDetentIdentifierChange: true)),
onDismiss: didDismiss) {
VStack {
Text("License Agreement")
.font(.title)
.padding(50)
Text("""
Terms and conditions go here.
""")
.padding(50)
Button("Dismiss",
action: { isShowingSheet.toggle() })
}
}
}
func didDismiss() {
// Handle the dismissing action.
}
}
在 SwiftUI 中,有三个不同的修饰符用于 popover、fullScreenCover 和 sheet,它们不允许开发者根据相同的真值来源(由 item
提供)显示不同样式的对话框。
使用 SheeKit,这是可能的 - 只需提供与您的 item
对应的 presentationStyle
。
struct ShowPartDetail: View {
@State var sheetDetail: InventoryItem?
var body: some View {
Button("Show Part Details") {
sheetDetail = InventoryItem(
id: "0123456789",
partNumber: "Z-1234A",
quantity: 100,
name: "Widget")
}
.shee(item: $sheetDetail,
presentationStyle: presentationStyle,
onDismiss: didDismiss) { detail in
VStack(alignment: .leading, spacing: 20) {
Text("Part Number: \(detail.partNumber)")
Text("Name: \(detail.name)")
Text("Quantity On-Hand: \(detail.quantity)")
}
.onTapGesture {
sheetDetail = nil
}
}
}
func didDismiss() {
// Handle the dismissing action.
}
var presentationStyle: ModalPresentationStyle {
var sheetProperties = SheetProperties()
sheetProperties.detents = sheetDetail?.quantity ?? 0 > 100500 ? [ .large() ] : [ .medium() ]
return .formSheet(properties: sheetProperties)
}
}
struct InventoryItem: Identifiable {
var id: String
let partNumber: String
let quantity: Int
let name: String
}
在 UIKit 中,UIViewController
类有许多属性,允许根据用例更改用户体验,例如禁止交互式关闭 sheet(通过 isModalInPresentation
),自定义状态栏外观、首选内容大小或模态转换样式。 不幸的是,此功能未在 SwiftUI 中公开。 SheeKit 通过允许使用者提供 UIViewControllerProxy
来解决此问题,该代理定义了呈现的视图控制器的首选参数。
struct ShowLicenseAgreement: View {
@State private var isShowingSheet = false
@State private var selectedDetentIdentifier = UISheetPresentationController.Detent.Identifier.medium
var body: some View {
Button(action: {
isShowingSheet.toggle()
}) {
Text("Show License Agreement")
}
.shee(isPresented: $isShowingSheet,
presentationStyle: .formSheet(properties: .init(detents: [ .medium(), .large() ], selectedDetentIdentifier: $selectedDetentIdentifier, animatesSelectedDetentIdentifierChange: true)),
presentedViewControllerParameters: presentedViewControllerParameters,
onDismiss: didDismiss) {
VStack {
Text("License Agreement")
.font(.title)
.padding(50)
Text("""
Terms and conditions go here.
""")
.padding(50)
Button("Dismiss",
action: { isShowingSheet.toggle() })
}
}
}
func didDismiss() {
// Handle the dismissing action.
}
var presentedViewControllerParameters: UIViewControllerProxy {
var parameters = UIViewControllerProxy()
parameters.preferredStatusBarStyle = .darkContent
parameters.preferredStatusBarUpdateAnimation = .fade
parameters.isModalInPresentation = true
parameters.modalTransitionStyle = .flipHorizontal
return parameters
}
}
在 SwiftUI 中,当用户在 iPad 上将应用程序最小化到另一个应用程序之上的最小尺寸时,或当 popover 在 iPhone 上显示为 sheet 时,开发者无法在场景的紧凑尺寸类中获得 medium-detent sheet 而不是 popover。 popover 适应的 sheet 始终具有 .large()
detent。
SheeKit 允许开发者自定义此行为,并指定 popover 适应的 sheet 的 detents,以及首选的 popover 箭头方向和源矩形。
struct ShowLicenseAgreement: View {
@State private var isShowingSheet = false
@State private var selectedDetentIdentifier = UISheetPresentationController.Detent.Identifier.medium
var body: some View {
Button(action: {
isShowingSheet.toggle()
}) {
Text("Show License Agreement")
}
.shee(isPresented: $isShowingSheet,
presentationStyle: .popover(permittedArrowDirections: .top,
sourceRectTransform: { $0.offsetBy(dx: 16, dy: 16) },
adaptiveSheetProperties: .init(detents: [ .medium(), .large() ],
selectedDetentIdentifier: $selectedDetentIdentifier,
animatesSelectedDetentIdentifierChange: true)),
onDismiss: didDismiss) {
VStack {
Text("License Agreement")
.font(.title)
.padding(50)
Text("""
Terms and conditions go here.
""")
.padding(50)
Button("Dismiss",
action: { isShowingSheet.toggle() })
}
}
}
func didDismiss() {
// Handle the dismissing action.
}
}
如果您想在任何其他使用 SwiftPM 的项目中使用 SheeKit,请在 Package.swift
中将该包添加为依赖项
dependencies: [
.package(name: "SheeKit", url: "https://github.com/edudnyk/SheeKit.git", from: "2.0.0"),
]
接下来,将 SheeKit 添加为您的测试目标的依赖项
targets: [
.target(name: "MyApp", dependencies: ["SheeKit"], path: "Sources"),
]
如果您使用 Carthage,您可以将以下依赖项添加到您的 Cartfile
github "edudnyk/SheeKit" ~> 2.0.0
如果您的项目使用 CocoaPods,请将 pod 添加到 Podfile 中的任何适用目标
target 'MyApp' do
pod 'SheeKit', '~> 2.0.0'
end
DismissAction
ModalPresentationStyle
ModalPresentationStyleCompat
SheetProperties
UIViewControllerProxy