欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

swift和swiftui_在SwiftUI 2.0中使用OutlineGroup和DisclosureGroup构建可扩展列表

程序员文章站 2022-04-09 21:42:26
...

swift和swiftui

Building an expandable list with nested items is quite a complex and error prone task to implement when using UITableView in UIKit. Luckily with SwiftUI 2.0, Apple introduced OutlineGroup and DisclosureGroup. With the views in our arsenal, we can build a hierarchical expandable and collapsible list with minimal lines of code using declarative syntax and reactive state management.

UIKit使用UITableView ,要实现一个带有嵌套项目的可扩展列表,这是一项非常复杂且容易出错的任务。 幸运的是,借助SwiftUI 2.0,Apple引入了OutlineGroupDisclosureGroup 。 利用我们的工具库中的视图,我们可以使用声明性语法和React性状态管理,以最少的代码行构建层次结构可扩展和可折叠的列表。

我们将建立什么 (What We Will Build)

We’re going to explore about OutlineGroup and DisclosureGroup, and how we can use them in practice to build List that represent hierarchical data in the UI by building three different kind of screens:

我们将探讨OutlineGroupDisclosureGroup ,以及如何在实践中使用它们通过构建三种不同类型的屏幕来构建表示UI中分层数据的List

  1. Using List to render hierarchical data.

    使用List呈现层次结构数据。

  2. Using OutlineGroup in List to handle multiple kind of views.

    在List中使用OutlineGroup处理多种视图。

  3. Using DisclosureGroup for expandable/collapsible behavior to group of views with state binding.

    使用DisclosureGroup的可扩展/可折叠行为将视图绑定到具有状态绑定的视图组。

You can download the completed project from the GitHub Repository.

您可以从GitHub Repository下载完成的项目。

You can also watch the full video tutorial from YouTube.

您也可以观看YouTube上的完整****。

使用列表呈现层次结构数据 (Using List to Render Hierarchical Data)

Let’s move on to the first example, which is showing list of items that have nested items inside of them.

让我们继续第一个示例,该示例显示其中包含嵌套项目的项目列表。

swift和swiftui_在SwiftUI 2.0中使用OutlineGroup和DisclosureGroup构建可扩展列表
Hierarchical Nested Expandable List
分层嵌套可扩展列表

By looking at the screenshoot above, we can see that at the root level, we have items such as Computers, Smartphones, Tablets, and, Wearables.

通过查看上面的屏幕快照,我们可以看到在根级别上我们有诸如计算机,智能手机,平板电脑和可穿戴设备之类的项目。

Inside the Computers, we have desktop and laptops. Inside the desktops, we have the children such as iMac, Mac Mini, Mac Pro. For the children of the Laptops, we have MacBook Pro, MacBook Air, and MacBook Pro. In this case, the depth of the Computers category is 3.

在计算机内部,我们有台式机和笔记本电脑。 在台式机内部,我们拥有诸如iMac,Mac Mini,Mac Pro之类的子级。 对于笔记本电脑的孩子,我们提供MacBook Pro,MacBook Air和MacBook Pro。 在这种情况下,“计算机”类别的深度为3。

Inside the smartphones, we have the children such as iPhone 11, iPhone XS, iPhone XR, iPhone X, iPhone SE. In this case the depth of the Smartphones category is 2.

在智能手机内部,我们有孩子,例如iPhone 11,iPhone XS,iPhone XR,iPhone X,iPhone SE。 在这种情况下,“智能手机”类别的深度为2。

Let’s dive into Xcode and learn how SwiftUI can help us to build this UI with very minimal lines of code. Create a new Xcode Project, give it any name that you prefer to.

让我们深入研究Xcode,了解SwiftUI如何可以帮助我们以最少的代码行来构建此UI。 创建一个新的Xcode项目,为其提供任何您喜欢的名称。

创建物品模型 (Create Item Model)

struct Item: Identifiable {
let id = UUID()
let title: String
let children: [Item]?
}

First, we’ll create a model to represent the item in the list. Create a new file named Item.swift. Declare the Item as a struct that conforms to Identifiable. Let’s declare the id property to satisfy the protocol requirement. We’ll use UUID as the type of the id as well as assigning it with default value. When we initialize UUID instance using the default initializer, the value will be unique.

首先,我们将创建一个模型来表示列表中的项目。 创建一个名为Item.swift的新文件。 将Item声明为符合Identifiablestruct 。 让我们声明id属性以满足protocol requirement 。 我们将使用UUID作为id的类型,并为其分配默认值。 当我们使用默认的initializer程序初始化UUID实例时,该值将是unique

Next, let’s declare the title property with type of String, we’ll use this to render the Text. Continuing on, to represent the children in the model, we need to declare a property containing the Array of the Item as this will be used by SwiftUI to determine whether the current item has children in the hierarchy. Let’s declare and named it as children.

接下来,让我们声明String类型的title属性,我们将使用它来呈现Text 。 继续,以表示模型中的children ,我们需要声明一个包含Array of the Item属性,因为SwiftUI将使用该属性来确定当前项目在层次结构中是否具有子代。 让我们声明并将其命名为children

创建ItemList UI (Create ItemList UI)

Let’s move on to build the View. Create a new file named ItemList.swift. Declare an instance property named items which is an array of Item. Inside the body implementation, we just need to initialize List passing the items. To enable the nesting of the children, we need to pass the keypath property name that contains the array of the Item to the children parameter. In our case, we pass the \.children as the keypath. Inside the view builder closure, we just need to render the Item inside the text using the title property.

让我们继续构建视图。 创建一个名为ItemList.swift的新文件。 声明一个名为items的实例属性,该属性是array of Itemarray of Item 。 在body实现内部,我们只需要初始化List并传递items 。 为了使nesting了的children ,我们需要通过keypath包含数组属性名Itemchildren parameter 。 在本例中,我们将\.children keypath作为keypath 。 在视图构建器闭包内部,我们只需要使用title属性在文本内呈现Item

Before we can preview the UI, we need to inject the Stub data into the preview. At the bottom of the source file, create an extension for the Item to help us stub the model. Declare the static constant stubs with type of Item Array. The first item will be computers, it has 2 children, desktops, and laptops. The desktops has 3 children: iMac, Mac Pro, and Mac Mini. The laptops has 2 children: MacBook Pro and MacBook Air. Let’s try this first, we just need to pass this when initializing the ItemList inside the preview like so.

在预览UI之前,我们需要inject Stub数据注入到预览中。 在源文件的底部,为Item创建extension ,以帮助我们对模型进行存根。 用Item Array类型声明static constant stubs 。 第一项是计算机,它有2个孩子,台式机和笔记本电脑。 台式机有3个子级:iMac,Mac Pro和Mac Mini。 笔记本电脑有2个孩子:MacBook Pro和MacBook Air。 让我们先尝试一下,像这样在预览中初始化ItemList时只需传递它。

struct ItemList_Previews: PreviewProvider {
static var previews: some View {
ItemList(items: Item.stubs)
}
}

The computers is shown in the preview with a disclosure indicator. To enable interaction in the live preview, make sure to press on the play button. Click on the indicator to make it expands to show the desktops and laptops. Try to also expand the desktops and laptops. As you can see with only 3 lines of UI related code, we’re able to show hierarchical nested data inside our SwiftUI list! It works recursively until the item has no more children.

预览中显示了带有公开指示符的计算机。 要在实时预览中启用交互,请确保按下播放按钮。 单击指示器使其展开以显示台式机和笔记本电脑。 尝试同时扩展台式机和笔记本电脑。 如您所见,只有3行与UI相关的代码,我们能够在SwiftUI列表中显示hierarchical nested data ! 它recursively起作用,直到该项目no more children

在列表中对多个视图使用OutlineGroup (Using OutlineGroup in List for Multiple Kind of Views)

You might be thinking, how can we display different kind of views and data in the list. No worries, we can use the new OutlineGroup to handle this scenario. Let’s take a look at the second screen we’ll build!

您可能在想,我们如何在列表中显示不同类型的视图和数据。 不用担心,我们可以使用新的OutlineGroup来处理这种情况。 让我们看一下我们要构建的第二个屏幕!

swift和swiftui_在SwiftUI 2.0中使用OutlineGroup和DisclosureGroup构建可扩展列表
Sidebar List with Different Expandable Sections
侧栏列表具有不同的可扩展部分

We have a Sidebar List containing menu items. At the top we, have the home menu, then at the middle section, we have the hierarchical items we have created before, finally at the bottom, we have the settings section which is also expandable containing the Account, Help, and Logout menu.

我们有一个包含菜单项的Sidebar List 。 在顶部,有home菜单,然后在中间部分,有我们之前创建的分层项目,最后在底部,有设置部分,该部分也可以expandable包含AccountHelpLogout菜单。

Let’s create a new SwiftUI view named SidebarList.swift. Declare an instance property named items which is an array of Item model. Let’s pass the stub items in the preview class to the initializer and activate the live preview.

让我们创建一个名为SidebarList.swift的新SwiftUI视图。 声明一个名为items的实例属性,该属性是Item模型的数组。 让我们将Preview类中的存根项目传递给初始化程序并**实时预览。

In the body implementation, declare an empty List, also add a ListStyle modifier passing the newly available SidebarListStyle. This style is suitable for sidebar list of menus especially in iPad.

body实现中,声明一个空的List ,还添加一个ListStyle修饰符,以传递新可用的SidebarListStyle 。 此样式特别适用于iPad的侧边栏菜单列表。

At the top of view builder closure, declare a Label passing Home as the `title` and house as the systemImage. Label is a new view in SwiftUI 2.0 that renders a text as the leading item and a SF Symbol Image as the trailing item.

在视图构建器关闭的顶部,声明一个将Home传递为Labelhouse传递给systemImageLabel是SwiftUI 2.0中的一个新视图,该视图将文本作为前导项目,将SF符号图像作为尾随项目。

To render our hierarchical items, we can use the OutlineGroup passing the array of items and keypath of the children property containing the array of the items. In the view builder closure, we can just render a text using the title of the item. Using the live preview, try to expand and collapse the items from the live preview to make sure it works.

要渲染层次项,我们可以使用OutlineGroup传递array of items和包含array of the items keypath of the children属性的keypath of the children 。 在视图构建器关闭中,我们可以使用项目的标题来呈现文本。 使用实时预览,尝试扩展和折叠实时预览中的项目以确保其有效。

Let’s move to the bottom section. By using SidebarListStyle as the ListStyle, we can use the Section View, this will add the expand and collapse behavior automatically for the views inside.

让我们转到底部。 通过使用SidebarListStyle作为ListStyle ,我们可以使用Section View,这将automatically为内部视图添加展开和折叠行为。

Let’s implement this, declare a Section, then pass the Text with Setting string as the Header. In the view builder, declare the 3 labels for account, help, and logout. Finally, add the Divider between each section.

让我们实现它,声明一个Section ,然后传递带有Setting字符串的Text作为Header。 在视图构建器中,为帐户,帮助和注销声明3个标签。 最后,在每个部分之间添加Divider

Run the live preview, the settings section now provides the disclosure indicator where we can use it to expand or collapse the section. Awesome!

运行实时预览,设置部分现在提供了公开指示器,我们可以在其中使用它来展开或折叠该部分。 太棒了!

使用DisclosureGroup的可扩展/可折叠行为对具有状态绑定的视图组 (Using DisclosureGroup for Expandable/Collapsible Behavior to Group of Views with State Binding)

Last, i want to show you the DisclosureGroup view which we can use to add expand and collapse behavior for a group of views within the same hierarchy. Let’s take a look at the screenshoot below.

最后,我想向您展示DisclosureGroup视图,我们可以使用该视图为同一层次结构中的一组视图添加展开和折叠行为。 让我们看一下下面的屏幕截图。

swift和swiftui_在SwiftUI 2.0中使用OutlineGroup和DisclosureGroup构建可扩展列表
Form List with DisclosureGroup
带有DisclosureGroup的表单列表

At the top of the Form, we have the personal information section containing textfields for names and email. Then, we have a datepicker for birthday. The section within the form can be collapsed and expanded, and the default state for the personal info section is expanded.

在表格顶部,我们有个人信息部分,其中包含姓名和电子邮件的textfields 。 然后,我们有一个生日的datepicker 。 表单中的部分可以折叠和展开,个人信息部分的default state也可以展开。

In the next section, we have a preferences notification section. It has three toggles where user can opt-in to receive notifications via email, sms, and push notification. The default state for the section is collapsed.

在下一部分中,我们有一个首选项通知部分。 它具有三个toggles按钮,用户可以在其中选择通过电子邮件,短信和推送通知接收通知。 该部分的default state为折叠状态。

Let’s go back to Xcode and implement the form using DisclosureGroup. Create a new SwiftUI file named FormList.swift.

让我们回到Xcode并使用DisclosureGroup实现表单。 创建一个名为FormList.swift的新SwiftUI文件。

In the body implementation, declare Form as the root view. Inside the view builder, declare a DisclosureGroup. Inside view builder, the Let’s declare the texfields and DatePicker. For the simplicity of this example, i just passed an inline constant as the binding instead of passing state properties. Let’s set the label parameter with Text passing Personal Information string. This syntax is part of the multiple trailing closure feature of Swift 5.3.

body实现中,将Form声明为根视图。 在视图构建器内部,声明DisclosureGroup 。 在视图构建器内部,让我们声明texfieldsDatePicker 。 为了简化本示例,我只是传递了一个inline constant作为binding而不传递状态属性。 让我们通过传递个人信息字符串的Text设置label parameter 。 此语法是Swift 5.3的multiple trailing closure功能的一部分。

Let’s see the result in the live preview by clicking on the disclosure indicator to expand and collapse the section.

通过单击公开指示器以展开和折叠该部分,让我们在实时预览中查看结果。

Next, let’s declare the notification preferences section. Declare a DisclosureGroup. Inside the view builder, declare the three toggles. For the label, just pass the Text containing the notification preferences setting.

接下来,让我们声明“通知首选项”部分。 声明一个DisclosureGroup 。 在视图构建器内部,声明three toggles 。 对于label ,只需传递包含通知首选项设置的Text

To control the expand and collapse state of a DisclosureGroup manually, we can pass a binding containing a boolean. Let’s declare a state property isProfileSectionExpanded and assign true as the default value. On the Profile DisclosureGroup, we can `pass the binding of the state to the isExpanded parameter.

manually控制DisclosureGroup的展开和折叠状态,我们可以pass a binding containing a boolean 。 让我们声明一个状态属性isProfileSectionExpanded并将true分配为default value 。 在Profile DisclosureGroup ,我们可以将状态绑定传递给isExpanded parameter

Let’s rebuild the app and run the live preview. As we can see, the profile section has an expanded state as the default behavior.

让我们重建应用程序并运行实时预览。 如我们所见,概要文件部分具有扩展状态作为默认行为。

结论 (Conclusion)

That’s it for this quick and practical example of how we can build a List with hierarchical data using OutlineGroup and Disclosure Group.

就是这个快速而实际的示例,它说明了我们如何使用OutlineGroup和Disclosure Group使用分层数据构建List。

You can watch the related WWDC 2020 session to learn more about how the view work. You will be amazed that in at implementation level, Apple basically used DisclosureGroup and OutlineGroup recursively to enable the nesting for List and OutlineGroup!

您可以观看相关的WWDC 2020会议,以了解有关该视图如何工作的更多信息。 您会惊奇地发现,在实现级别,Apple基本上递归地使用DisclosureGroup和OutlineGroup为List和OutlineGroup启用嵌套!

Until the next one, lets keep the lifelong learning goes on!

直到下一个,让我们继续进行终身学习!

翻译自: https://medium.com/@alfianlosari/building-expandable-list-with-outlinegroup-disclosuregroup-in-swiftui-2-0-aa9dda14bbab

swift和swiftui

相关标签: python java