侧边栏壁纸
  • 累计撰写 28 篇文章
  • 累计创建 10 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

使用List构建Menu

Jserv
2025-04-28 / 0 评论 / 0 点赞 / 9 阅读 / 8166 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2025-04-28,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

[本文翻译自hackingwithswift,点击链接阅读原文]

我们将从简单开始,然后向上努力。一路上,你会开始看到SwiftUI让一些变得简单的事情,以及一些更难的事情。

在ContentView.swift中,是一个基本结构,代表我们应用程序中唯一的屏幕:ContentView。看起来像这样:

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.accentColor)
            Text("Hello, world!")
        }
        .padding()
    }
}

这不是很多代码,但它已经告诉我们很多:

  1. 视图是SwiftUI中的结构。

  2. 所有视图都必须符合View协议。

  3. 该协议需要一个名为body的计算属性,其中包含视图的实际布局。

  4. 它返回some View,这是一个名为不透明返回类型的Swift功能——它的意思是“一种特定类型的视图,但我们真的不在乎是哪种视图。”

  5. 在我们的内容视图中是少量的用户界面:显示地球图标的图像和一些写着“你好,世界”的文字,两者都被包裹在VStack中,使其垂直对齐。随着我们的进展,我们将更详细地查看这些观点。

  6. 有一些方法调用到位:.imageScale().foregroundStyle()padding()在SwiftUI中,我们调用这些修饰符,因为它们修改了文本视图的外观或行为方式。

您还应该在Xcode的右侧看到一个预览面板。这会随着您键入而更新,这使得它成为在您工作时查看更改的好方法。如果您没有看到右侧的预览面板,请转到“编辑器”菜单并选取“画布”。

如果Xcode的预览区域停止——这种情况经常发生——您可以按Opt-Cmd-P使其恢复显示您的布局。

这真的很重要,所以我重复一遍:按Opt-Cmd-P将使您的SwiftUI预览更新。

在我们的应用程序中,此屏幕将向我们显示菜单中的项目列表,因此我们将使用List视图,而不是Xcode的默认模板代码。

因此,用这个替换当前文本视图:

List {
    Text("Hello World")
    Text("Hello World")
    Text("Hello World")
}

当预览更新时,您现在将看到相当于UIKit的UITableView的三段文本,都写着“Hello World”。这是一个静态列表视图——我们正在发送三段固定数据,因此它将它们解释为表格中的三行。

在我们的应用程序中,菜单将包含可以订购的项目列表,点击其中一个将显示一个新屏幕,其中包含有关该订单项目的详细信息。这就像在UIKit中一样:我们在导航控件中包装表格。

在SwiftUI中,这个导航控件是一个NavigationStack,它结合了UINavigationBar的显示样式和UINavigationController的视图控制器堆栈行为。要带一个,只需在您的列表周围添加NavigationStack,如下:

NavigationStack {
    List {
        Text("Hello World")
        Text("Hello World")
        Text("Hello World")
    }
}

当预览更新时,你会看到事情看起来一样,但这只是因为我们还没有给它起一个标题。

早些时候,我简要地提到了padding()修饰符,说修饰符之所以得名,是因为它们修改了视图的外观或行为方式。SwiftUI有许多修饰符——数百个,很容易——每个修饰符都允许您以一种非常具体的方式自定义视图的行为。

是的,修饰符看起来像普通的Swift方法,但它们更复杂,因为它们实际上改变了它们所应用的内容。简单来说,如果您有一些文本并应用padding()修饰符,您不仅会返回一些文本,而且周围有一些空间——您实际上会返回另一种类型

在这种情况下,我们想将navigationTitle()修饰符应用于我们的列表视图,该视图接受在导航栏中显示的某种文本。所以,我们会这样写:

NavigationStack {
    List {
        Text("Hello World")
        Text("Hello World")
        Text("Hello World")
    }
    .navigationTitle("Menu")
}

是的,修饰符附加到列表而不是导航堆栈上——想想我们如何设置UIViewController的标题,而不是尝试设置UINavigationController的标题。

如果您现在尝试运行该应用程序,您会看到一切都完全按照我们预期的工作——表格滚动,导航栏随着您滚动而缩小,等等。SwiftUI做的一件伟大的事情是默认为我们提供现代系统行为,因此我们获得大导航栏标题作为标准。

当您有固定的表格单元格时,静态文本工作正常,但就我们而言,我们有很多菜单项目可以加载到多个部分——早餐、主菜、甜点和饮料。我们真正想做的是从JSON中加载菜单数据,然后将其用于我们的列表项,这实际上并不难完成。

首先,我们需要加载我们的数据。您已导入的Helper.swift文件包含从应用程序捆绑包中加载CodableJSON的代码,非常适合加载我们的menu.json文件。因此,现在将此属性添加到ContentView结构中:

let menu = Bundle.main.decode([MenuSection].self, from: "menu.json")

接下来,我们需要将我们的列表放在菜单上的各个部分。这是通过使用ForEach块来完成的,该块循环数组中的项目,并重复其中的任何东西:

List {
    ForEach(menu) {
        Text("Hello World")
        Text("Hello World")
        Text("Hello World")
    }
}

ListForEach之后的开头大括号实际上表示闭包的开始,在ForEach的情况下,SwiftUI将把数组中的每个部分传递到闭包中,以便我们可以配置它。

因此,我们需要通过将代码修改为以下内容来接受该部分:

ForEach(menu) { section in

几乎有用,但还有一件事我们需要做。SwiftUI需要知道如何识别我们表格中的每个单元格——它需要确切地知道哪个是哪个,这样如果我们要求的话,它可以为我们添加和删除一些东西。当我们有一个静态列表时,这不是问题,因为它可以看到有三个,但现在我们有一个动态列表,我们需要告诉它关于每个部分的东西,使其独一无二。

如果您打开Menu.swift,您将看到定义MenuSectionMenuItem的结构,两者都有包含UUIDid属性——一个通用唯一标识符。这非常适合我们使用,因为每个部分的每个菜单项都有一个唯一的标识符,因此SwiftUI可以知道哪个是哪个。

我们可以通过使两种类型符合Identifiable来告诉SwiftUI使用这些标识符。该协议只有一个要求,即符合类型必须有一个名为id的属性,可以唯一地识别它们。我们已经有了,所以只需将Identifiable添加到这两种类型中就足够了:

struct MenuSection: Codable, Identifiable {

并且:

struct MenuItem: Codable, Equatable, Identifiable {

如果您现在运行代码,您将看到十二行包含“Hello World”——这是您可能没有想到的。

改变的是,我们现在有一个动态列表,我们的ForEach将为菜单部分中的每个项目执行其闭包的正文——三个文本视图——一次。我们有四个部分,每个部分都有三个文本视图,所以我们总共有12个。

为了解决这个问题,我们将要求每个部分提供一个文本视图,并给它我们要显示的部分名称:

List {
    ForEach(menu) { section in
        Text(section.name)
    }
}

接下来,让我们在每个部分中添加项目。这是ForEach部分中的另一个ForEach,像这样:

List {
    ForEach(menu) { section in
        Text(section.name)

        ForEach(section.items) { item in
            Text(item.name)
        }
    }
}

现在,您将看到许多表格行,其中一些包含部分名称(“早餐”、“主菜”等),一些包含菜单项名称(“全英文”、“超级食品沙拉”等)。

虽然这有效,但它并不理想——它不会在我们的表格中创建任何视觉结构,所以我们将把它拆散。标准的UIKit方法是使用表格视图部分,而SwiftUI为此为我们提供了Section视图。我们可以用Section名称作为标题替换Text(section.name),该部分将用作部分开头的文本。内部的ForEach——包含我们的菜单项的那个——就在该部分,因此SwiftUI将了解我们如何将内容分组在一起。

最终结果如下所示:

List {
    ForEach(menu) { section in
        Section(section.name) {
            ForEach(section.items) { item in
                Text(item.name)
            }
        }
    }
}

默认情况下,SwiftUI的列表使用UITableView的“嵌套分组”样式,但我们可以通过在navigationTitle()后添加另一个修饰符来更改它:

.listStyle(.grouped)

SwiftUI列表现在整齐地分成分组部分。

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区