SwiftUI中的CustomPresentationDettent协议实现了模态演示
#ios #swift #swiftui #xcode

您也可以直接在我的个人博客https://amarildo.codes

中阅读本文

我们可以构建更灵活,定制的 模态视图演示,感谢CustomPresentationDetent 协议。在显示模态视图时,通常使用.sheet修饰符。但是,有时我们可能需要对演示文稿的更多控制,而.sheet的默认行为还不够。 这是 CustomPresentationDetent实现开始的地方,因为它使我们能够在模态视图中更改演示文稿的行为。

你会学到什么

本文提供并概述了有关如何使用CustomPresentationDetent的分步指南。您将说明如何创建PresentationDetent struct 的扩展名并实现CustomPresentationDetent 协议。。

  1. starter project

  2. 开始
  3. 创建PresentationDetent扩展

  4. 实施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通过使用 emwory dismiss属性来否定 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。如果我们想更改此行为,我们可以使用两行代码更改此行为。

  1. 添加一个名为PresentationDetentselectDetent的私人属性,并以.height(64)的值初始化。
struct ContentView {
    // ...

    @State private var selectDetent: PresentationDetent = .height(64)
}
  1. 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 属性,并为它们分配了mediumlarge 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

感谢您的阅读和快乐的建筑! :)