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

目 录CONTENT

文章目录

SwiftUI中的双向绑定

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

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

如果您在SwiftUI预览窗口中查看,您将看到标准的iOS选择器界面——一个弹出的选项菜单。默认情况下,它将显示第一个选项,因为它读取了paymentType的值,我们将其设置为“现金”。然而,当用户显示菜单时,他们的选择会发生变化——他们可能会选择“信用卡”或“iDine积分”而不是现金。

因此,这个选择器不仅读取paymentType的值,还写入值。这就是所谓的双向绑定,因为对paymentType值的任何更改都将更新拣选器,对拣选器的任何更改都将更新paymentType

This is where the dollar sign comes in: Swift property wrappers use that to provide two-way bindings to their data, so when we say $paymentType SwiftUI will write the value using the property wrapper, which will in turn stash it away and cause the UI to refresh automatically.

乍一看,所有这些@和$s可能看起来有点不迅速,如果你来自UIKit,你可能不习惯以这种方式工作。然而,它们允许我们获得需要很多麻烦的功能:

  • 没有@State我们将无法更改结构中的属性,因为结构是固定值。

  • 没有StateObject我们将无法创建在应用程序期间保持活力的类。

  • 如果没有@EnvironmentObject我们将无法从应用程序中的其他地方接收共享数据。

  • 如果没有ObservableObject当外部值发生变化时,我们就不会收到通知。

  • 如果没有$property双向绑定,我们需要手动更新值。

无论如何,这是我们的基本选择器完成,因此如果我们返回OrderView.swift,我们可以更新我们的代码,以便它显示我们新的CheckoutView结构,而不是一些显示“Checkout”的文本。

找到这个代码:

NavigationLink("Place Order") {
    Text("Check out")
}

并用这个替换它:

NavigationLink("Place Order") {
    CheckoutView()
}

现在尝试运行应用程序,然后转到“订单”标签,然后按“下订单”。结果是......嗯,不太完美,让我们这样说吧。尽管为了走到一步付出了很多努力。

好吧,我们将在CheckoutView.swift中只更改一个单词,这应该会让所有工作都感到合理。

CheckoutView,我想让你将VStack更改为Form,然后按Cmd+R再次尝试该应用程序。你能发现区别吗?

以前,我们有一个没有标题的普通弹出菜单,但现在我们处于一个表单中,我们得到了一个表格行,显示我们的选择器的标题及其当前选定的值。

SwiftUI调整了我们的表单,将图片显示为表单中的单行。

这就是SwiftUI对用户界面的声明方法的力量:我们说出我们想要的行为,而不是它的精确风格,SwiftUI将根据其使用的上下文自动调整它。

让我们通过添加两个组件继续我们的表格:一个允许用户选择他们是否有iDine会员卡,另一个允许他们输入卡号。两者都需要双向绑定,就像我们的选择器一样,所以让我们从两个新的@State属性开始:

@State private var addLoyaltyDetails = false
@State private var loyaltyNumber = ""

现在,我们可以将控件添加到我们的表单中来表示这些——Toggle等同于UISwitchTextField等同于UITextField。在我们现有的表格部分中添加这两个:

Toggle("Add iDine loyalty card", isOn: $addLoyaltyDetails)
TextField("Enter your iDine ID", text: $loyaltyNumber) 

那里没有很多代码,但值得一提的是一些细节:

  1. 两个控件都绑定到我们刚刚制作的那些@State属性。

  2. Toggle开关里面有一些文本,这些文本将自动显示在左侧作为描述。

  3. TextField有一些占位符文本,因此用户知道要在那里输入什么。

在你运行应用程序之前,我想先谈谈另一个变化。我们刚刚添加的那个文本字段——它应该一直在那里,还是只有在启用切换开关时才存在?

我们绑定了ToggleaddLoyaltyDetails的值,这意味着当用户打开或关闭它时,Boolean将设置为true或false。如果文本字段只有在打开切换时才可见,那不是很好吗?

嗯,事实证明这很容易做到。尝试在以下条件下包装文本字段:

Toggle("Add iDine loyalty card", isOn: $addLoyaltyDetails)

if addLoyaltyDetails {
    TextField("Enter your iDine ID", text: $loyaltyNumber)
}

当您现在运行程序时,您会看到更改切换状态会显示或隐藏文本字段。如果你想清楚,这一切都应该有意义:

  • 切换对addLoyaltyDetails属性有双向绑定。

  • 这意味着当切换被更改时,属性会更新。

  • 该属性标有@State

  • 当任何@State@EnvironmentObject更改其值时,SwiftUI将重新调用body属性。

  • body属性直接读取addLoyaltyDetails的值,以决定是否创建文本字段。

为了改善效果,请修改Toggle上的绑定,使其动画化它引起的任何变化:

Toggle("Add iDine loyalty card", isOn: $addLoyaltyDetails.animation())

这将导致会员卡行顺利地滑入和滑出。

让我们尝试另一个常见的控制:分割控制。在SwiftUI中,这实际上只是一个带有修饰符的Picker,因此它的工作方式完全相同——我们给它一个双向绑定来存储其选择,然后使用ForEach在数组上循环,以创建一些选项可供选择。

对于这个屏幕,我们可以使用分段控件来表示用户可以选择的各种提示百分比。因此,首先添加此属性来存储我们想要显示的选项:

let tipAmounts = [10, 15, 20, 25, 0]

现在添加此属性来存储所选的小费金额:

@State private var tipAmount = 15

我们现在可以将所有这些放入我们的表格中的分割控制中。我将把这个放在我们表格的新部分,因为它允许我们添加一个标题,使用户界面更清晰:

Section("Add a tip?") {
    Picker("Percentage:", selection: $tipAmount) {
        ForEach(tipAmounts, id: \.self) {
            Text("\($0)%")
        }
    }
    .pickerStyle(.segmented)
}

我们将在我们的表格中再添加一个组件,这是一个实际确认订单的按钮。我们一会儿就会回到它的确切功能,因为我们首先需要看看其他东西。

这是表格的最后一部分:

Section("Total: $100") {
    Button("Confirm order") {
        // place the order
    }
}

是的,我知道总订单价值是错误的,但现在只需运行应用程序。

我们在ItemDetail中添加了一个按钮,它是透明背景上的蓝色文本,以屏幕为中心。现在,我们的表单中有一个按钮,它与众不同:它是蓝色文本,左对齐,如果你点击它,整个行会闪烁灰色。这是SwiftUI的表单系统改变其内部组件设计和行为的另一个例子。

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区