您也可以直接在我的个人博客https://amarildo.codes
中阅读本文
我们可以构建更灵活,定制的 模态视图演示,感谢CustomPresentationDetent
协议。在显示模态视图时,通常使用.sheet
修饰符。但是,有时我们可能需要对演示文稿的更多控制,而.sheet
的默认行为还不够。 这是 CustomPresentationDetent
实现开始的地方,因为它使我们能够在模态视图中更改演示文稿的行为。
你会学到什么
本文提供并概述了有关如何使用CustomPresentationDetent
的分步指南。您将说明如何创建PresentationDetent
struct 的扩展名并实现CustomPresentationDetent
协议。。
- 开始
-
创建
PresentationDetent
扩展 -
实施
CustomPresentationDetent
入门项目开始
在我们开始之前
git clone git@github.com:amarildolucas/CustomPresentationDetent.git
cd CustomPresentationDetent
git checkout start-project
-
main
分支包含实现的最终结果。 -
start-project
branch 包含您应该使用本文遵循的版本。强烈建议您使用start-project
branch 。
开始项目包含一个ContentView.swift
文件,该文件:
-
定义了swiftui视图。
-
包含一个按钮,按下时, 切换
isPresentingSheet
的布尔值,使用.sheet
修饰符呈现模态床单。模态表的内容是在称为ContentModalSheet
的单独 struct 中定义的。ContentView
struct 也符合 view 协议,并具有返回包含按钮的VStack
的主体属性。
// ContentView.swift
struct ContentView {
// Used to toggle and present the modal sheet.
@State private var isPresentingSheet: Bool = false
}
extension ContentView: View {
// Returns a VStack containing the button.
var body: some View {
VStack {
Button(action: presentSheet) {
HStack {
Image(systemName: "arrow.up")
Text("Present Sheet")
}
.fontWeight(.semibold)
.foregroundColor(.white)
.padding()
.background(Color.accentColor)
.cornerRadius(8)
}
.sheet(
isPresented: $isPresentingSheet,
content: ContentModalSheet.init
)
}
.padding()
}
}
extension ContentView {
// Toggles the boolean value of isPresentingSheet and presents a modal sheet using the .sheet modifier.
private func presentSheet() {
isPresentingSheet.toggle()
}
}
开始项目还包含另一个名为ContentModalSheet.swift
的文件,该文件包含要显示的 view 。
-
定义了一个称为
ContentModalSheet
的视图,该视图以模态纸。 -
显示
Text
“显示模态表”和Button
,该23通过使用 emworydismiss
属性来否定 sheet
// ContentModalSheet.swift
struct ContentModalSheet {
@Environment(\\.dismiss) private var dismissModalSheet
}
extension ContentModalSheet: View {
var body: some View {
VStack {
ZStack {
Button(action: dismissModalSheet.callAsFunction) {
Image(systemName: "xmark")
}
.fontWeight(.semibold)
.foregroundColor(Color(uiColor: .label))
}
.frame(maxWidth: .infinity, alignment: .leading)
Spacer()
Text("Showing Modal Sheet")
.font(.title3)
Spacer()
}
.padding()
}
}
创建呈现内容扩展
.presentationDetents()
方法的直接实现设置了可用的vittents/static属性和方法( snap points ),以包含不同尺寸的 emply 演示文稿:
.large
.medium
.custom<D>(D.Type)
.fraction(CGFloat)
.height(CGFloat)
上述所有属性和方法返回PresentationDetent
实例。让我们通过检查.presentationDetents([.medium, .height(420), .large])
代码的.presentationDetents([.medium, .height(420), .large])
行中的鲍洛代码来查看这一点。
Button(action: presentSheet) {
HStack {
Image(systemName: "arrow.up")
Text("Present Sheet")
}
.fontWeight(.semibold)
.foregroundColor(.white)
.padding()
.background(Color.accentColor)
.cornerRadius(8)
}
.sheet(isPresented: $isPresentingSheet) {
ContentModalSheet()
.presentationDetents([.medium, .height(420), .large])
}
默认情况下, sheets 呈现PresentationDetent/large
detent。如果我们想更改此行为,我们可以使用两行代码更改此行为。
- 添加一个名为
PresentationDetent
的selectDetent
的私人属性,并以.height(64)
的值初始化。
struct ContentView {
// ...
@State private var selectDetent: PresentationDetent = .height(64)
}
- 将
selection
参数添加到.presentationDetents
方法中,并使用$selectDetent
变量分配。该方法将返回分配给该变量的选定的PresentationDetent
。
// Button... {}
.sheet(isPresented: $isPresentingSheet) {
ContentModalSheet()
.presentationDetents(
[.height(64), .medium, .height(420), .large],
selection: $selectDetent
)
}
为了进一步解释,A detent 是我们的模态呈现可以 snap 到达的位置。例如,如果我们有模态呈现,我们可以定义不同的 vitents 用于以不同尺寸或样式显示 view 。
现在我们了解了驱动器的工作原理,让我们将我们的vittents 扩展到一个称为PresentationDetent+Extension
的单独文件,然后向其添加以下代码。
extension PresentationDetent {
static let mediumBottomBar = Self.medium
static let largeBottomBar = Self.large
}
此代码在PresentationDetent
struct 中定义了两个 static 属性,并为它们分配了medium
和large
static 属性的原始值< em> struct 。如果我们想改善属性的上下文和命名法和功能实现。
在下一部分中,我们将走得更远,最后实施我们的自定义属性。
CustomPresentationDetent实现
要为我们的模态呈现实现CustomPresentationDetent
,我们需要创建一个符合协议的自定义 struct 。 协议包含返回可选 CGFloat
的A static 方法。
static func height(in context: Context) -> CGFloat?
所以,让我们创建我们的自定义 struct 并实现协议。
private struct BottomBarDetent: CustomPresentationDetent {
// Calculates and returns a height based on the context.
static func height(in context: Context) -> CGFloat? {
max(64, context.maxDetentValue * 0.1)
}
}
现在在我们的扩展名文件的顶部,我们可以添加一个使用我们自定义类型的新属性。
extension PresentationDetent {
static let bottom = Self.custom(BottomBarDetent.self)
// ...
}
和分别在我们现有的.presentationDetents
方法中,我们可以更新以使用我们的新自定义属性.bottom, .mediumBottomBar
和.largeBottomBar
。
// Button... {}
.sheet(isPresented: $isPresentingSheet) {
ContentModalSheet()
.presentationDetents(
[.bottom, .mediumBottomBar, .largeBottomBar],
selection: $selectDetent
)
}
概括
本文提供了有关如何使用CustomPresentationDetent
的详细说明。现在,如有必要,请在未来的SwiftUi项目中创建更灵活,可自定义的模态演示。
You can download the final project here.
如果您喜欢这篇文章,请考虑supporting me by offering me a coffee:
感谢您的阅读和快乐的建筑! :)