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

目 录CONTENT

文章目录

使用@EnvironmentObject向订单添加项目

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

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

那么,我们实际上刚刚做了什么?

好吧,我们想要一种方法,让用户查看菜单中的项目并将其添加到订单中。但我们希望他们订购的项目出现在应用程序的其他地方。

环境对象是SwiftUI在许多地方共享数据的方式,但它们本身并不是一个完整的解决方案,因为我们用户界面的不同部分很容易根据它们加载时间显示不同的东西。通过ObservableObject协议,我们赋予了Order类宣布它已更改的能力,我们现在可以让SwiftUI监视这些公告并重新加载UI。

我们刚刚创建了一个Order实例,并将其放入环境中。因此,来自ContentView的任何视图都可以读取该顺序并以某种方式操作它。

我们想从详细信息屏幕将项目添加到我们的订单中,因此请返回ItemDetail.swift并赋予它此属性:

@EnvironmentObject var order: Order

我们没有给它一个默认值,所以你可能会认为它会因为Swift的严格初始化规则而造成问题。然而,@EnvironmentObject属性包装器有一些魔术:它允许这个变量在代码中没有值,因为我们说它已经在环境中设置好了。

当显示此视图时,SwiftUI将自动在其环境对象列表中查找具有Order类型的东西,并将其附加到该属性中。如果找不到Order对象,那么我们就有问题了:我们说过的东西没有,我们的代码会崩溃。这就像一个隐式未包装的可选选项,所以要小心。

@EnvironmentObject是Swift中的另一个属性包装器,就像@Published@StateObject一样。这意味着我们得到了我刚才提到的自动附加功能,但也告诉SwiftUI监视对象的任何更改,并在更改公告通过时刷新其用户界面。

在我们添加一些代码来操作ItemDetail中的顺序之前,我们需要修复另一个预览问题。你看,我们现在承诺,当我们的ItemDetail显示时,Order类型的对象将出现在环境中,我们从iDineApp.swift创建并传递。当我们的应用程序真实运行时,这效果很好,但在Xcode预览中,我们不会从应用程序启动——我们是由视图文件末尾的PreviewProvider代码创建的。

只有当我们处于调试模式时,才会构建此预览代码——当我们从Xcode构建时,而不是用于App Store。这意味着将仅与我们的预览相关的代码放入那里是安全的,在这种情况下,这将是一个临时Order实例,以便它接收与实际运行时相同的数据:

struct ItemDetail_Previews: PreviewProvider {  
    static var previews: some View {
        NavigationStack {
            ItemDetail(item: MenuItem.example).environmentObject(Order())
        }
    }
}

这复制了我们在应用程序启动时的相同设置,这意味着我们的预览应该会再次工作。

现在我们可以进行真正的交易:添加一个按钮,将我们当前的菜单项添加到订单中。SwiftUI中的按钮由两部分组成:一个标题字符串和一个包含点击按钮时运行的代码的动作闭包。

Order类已经有一个add()方法,该方法需要一个菜单项,因此我们将将其用于操作。至于标题,我们只需添加一些文字,上面写着“订购这个”——如果您愿意,欢迎您添加更多样式!

将此放入ItemDetail的主体中,就在垫片之前:

Button("Order This") {
    order.add(item: item)
}
.buttonStyle(.borderedProminent)

这就是向共享订单添加内容所需的一切,但我们实际上还看不到任何东西。

为了实现这一点,我们需要创建一个显示用户到目前为止订单的新屏幕,然后将其放入带有我们现有内容视图的标签栏中。

因此,按Cmd+N来制作一个新的SwiftUI视图,称其为“OrderView”。因为这需要与我们应用程序的其他部分具有相同的Order实例,因此您需要赋予它与我们 gaveItemDetail相同的属性:

@EnvironmentObject var order: Order

以及其预览中的类似代码,以确保它也有效:

struct OrderView_Previews: PreviewProvider {  
    static var previews: some View {
        OrderView().environmentObject(Order())
    }
}

至于我们的OrderView的正文,这些都是你已经知道的东西:

  • 一个List视图,给我们一个滚动表。

  • 一些Section阻止我们拆分我们的信息。

  • ForEachHStack显示我们的订单项目数组,同时显示每个项目的名称和价格。

  • 结尾的第二个Section显示了下订单的导航链接。

  • 导航栏标题为“订单”。

把所有这些放在一起,给我们这个OrderView结构:

struct OrderView : View {
    @EnvironmentObject var order: Order

    var body: some View {
        NavigationStack {
            List {
                Section {
                    ForEach(order.items) { item in
                        HStack {
                            Text(item.name)
                            Spacer()
                            Text("$\(item.price)")
                        }
                    }
                }

                Section {
                    NavigationLink("Place Order") {
                        Text("Check out")
                    }
                }
            }
            .navigationTitle("Order")
        }
    }
}

提示:当您只想为NavigationLink一些文本时,您可以使用上面显示的更简单的初始化器,而不是提供label闭包。

我们很快就会回到那个,但首先我们需要通过我们的用户界面访问它来确保它工作正常。

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区