【问题标题】:SwiftUI - Struct Binding doesn't update UI as expectedSwiftUI - 结构绑定未按预期更新 UI
【发布时间】:2020-09-15 22:21:19
【问题描述】:

我有一个 SwiftUI 问题,看起来不像是已回答或与另一个问题重复,而且 SwiftUI 是相当新的。

根据我的理解,以下代码显示了 Button 控件的背景切换。喜欢的数量按预期增加,但状态更改似乎没有传递到 Book 结构。

我读到的所有内容都是在预览中,您需要使用: .constant(x) 在 PreviewProvider 的视图中。

但是,它不起作用,带有点赞的按钮既不是前景色,也不是背景色。

在调试应用程序时,isLiked 书的结果确实发生了变化。但是前景色/背景色没有。

这是视图的代码。

import SwiftUI

struct BookDetailView: View {

  @Binding var book: Book
    @State var likes: Int = 0
  var body: some View {
    VStack {

      Text(book.title)
      Image(book.imageName)
        .resizable()
        .aspectRatio(contentMode: .fit)
        .scaledToFit()

        Button(action: {
            self.book.isLiked.toggle()
            self.likes = self.likes + 1
        }) {
            Text("???? Like \(likes)")
                .padding()
                .foregroundColor(self.book.isLiked ? .secondary : .primary)
                .background(self.book.isLiked ? Color.rayWenderlichGreen : Color.white)
                .cornerRadius(10)
        }
    }
  }
}

struct BookDetailView_Previews: PreviewProvider {

  static var previews: some View {
    BookDetailView(book: .constant(Book.demoBooks.randomElement()!))
  }
}

这是实际的书籍模型

import SwiftUI

struct Book: Identifiable {
  var id = UUID()
  var title: String
  var imageName: String
  var isLiked = false
}

extension Book: Equatable {
  static func == (lhs: Book, rhs: Book) -> Bool {
    return lhs.id == rhs.id
  }
}

我花了一些时间试图了解为什么会发生这种情况,看起来这可能只是 SwiftUI 的一个错误。

有什么想法或建议吗?

【问题讨论】:

    标签: swift xcode binding swiftui


    【解决方案1】:

    我无法测试,因为没有提供 Book 类型,但如果它是一个结构,以下应该可以工作(注意:.constant 绑定是常量,它不会修改包装值,你需要一个活一个)

    struct BookDetailView_Previews: PreviewProvider {
      struct TestView: View {
         @State private var book = Book.demoBooks.randomElement()!
         var body: some View {
           BookDetailView(book: $book)
         }
      }
      static var previews: some View {
        TestView()
      }
    }
    

    更新:现在进行了修复 - 原因是制作平等的书没有考虑更改的 isLiked 状态,因此视图不会检测到任何更改并且不会更新。

    解决方案是删除该扩展名或使其考虑应指示修改值的所有字段,如下所示

    extension Book: Equatable {
      static func == (lhs: Book, rhs: Book) -> Bool {
        lhs.id == rhs.id && lhs.isLiked == rhs.isLiked
      }
    }
    

    经过测试并适用于 Xcode 11.4 / iOS 13.4

    【讨论】:

    • 我已经添加了图书模型。这是一个结构。也许我需要把它变成一个类并改变它以符合 ObservableObject?但这只会使任何动态的数据类型始终成为一个类,从而使 swift ui 概念比我想象的要复杂得多。
    • 添加您的代码并没有解决问题,书本按钮打开一次,然后不会关闭。就像视图重绘只触发一次...
    • 很棒的发现!标记为正确答案。似乎 equatable 函数通知结构中的更改。好东西。
    【解决方案2】:

    您的代码看起来还不错,并且您对 State 概念的理解、使用和实现看起来都不错。

    奇怪的是,这也发生在我身上。有时,State var 只是不会重新加载视图,我相信这是因为 SwiftUI 不稳定。我有几种方法可以“修复”它。

    1. 我创建了一个@State private var toggleMe: Bool! = false 并调用toggleMe.toggle() 以在需要更改状态时切换它。这有时会更新用户界面
    2. 我停止使用 States 并创建自定义 OberveableObject like in this tutorial,因为这样我可以通过调用 objectWillChange.send() 手动指示状态何时发生变化,并且由于某种原因,它似乎比更改 State var 效果更好李>

    这些建议都不是您的案例的好做法。它们只是处理 SwiftUI 显示的一些稳定性问题的一种方式,因为它是新的

    【讨论】:

    • 否 (2) 正是我认为我接下来必须去的地方。我不确定这是 SwiftUI 的限制、现有的错误还是它的设计方式。看起来 ObservableObject 和 ObservedObject 绝对是您强制进行此更新的方式。如果您正在为输入视图的数据进行大量表单编辑,则认为它会使整个结构片段变得毫无意义。
    • 环顾四周后,我找不到一个原因,为什么在一个View 中有一个@State 并将其作为@Binding 传递到一个提取的视图中,在更改绑定的值之后,状态的值不会第一次改变。如果你连续做两次它会起作用,但这对我不起作用。传入objectWillChange 发布者并调用它的发送为我解决了这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-06
    • 2011-02-25
    • 2020-12-08
    • 1970-01-01
    • 2020-04-04
    • 2021-11-22
    • 2018-08-08
    相关资源
    最近更新 更多