【问题标题】:Swiftui TextEditor seems not to respond to state changesSwiftui TextEditor 似乎不响应状态更改
【发布时间】:2023-02-01 05:38:32
【问题描述】:

当 SwiftUI TextEditor 在子视图中时,我无法使其正常工作。

这是一个向我展示问题的小例子:

import SwiftUI

struct ContentView: View {
  @State private var someText: String = "Hello World"
    var body: some View {
      VStack {
        HStack {
          Button("Text 1", action: {someText = "hello"})
          Button("Text 2", action: {someText = "world"})
        }
        ViewWithEditor(entry: $someText)
      }
    }
}

struct ViewWithEditor: View {
  @Binding var entry: String
  @State private var localString: String
  
  var body: some View
  {
    VStack {
      TextEditor(text: $localString)
    }
  }
  
  init(entry: Binding<String>) {
    self._entry = entry
    self._localString = State(initialValue: entry.wrappedValue)
    print("init set local String to: \(localString)")
  }
}

当我单击按钮时,我希望编辑器文本发生变化,但它仍保持其初始值。

打印语句显示正在更新“localString”变量。

TextEditor 坏了还是我遗漏了一些基本的东西??

如果将按钮移动到与 TextEditor 相同的视图中,直接更改本地状态变量,它会按预期工作。

这是在 MacOS 下运行的,以防它有所作为。

TIA 艾伦。

【问题讨论】:

  • 你为什么做这个?你能解释一下吗? self._localString = State(initialValue: entry.wrappedValue)
  • 好的,在实际的应用程序中,我将完整的结构传递给父视图,它正在拉出一个字段,以通过有点像这样的视图进行编辑。 “意图”是提供一个本地变量,可以在编辑结束时存储或放弃。我认为这将是方式。我继续玩,发现代理绑定确实可以完成这项工作。请参阅下面的答案。谢谢你考虑一下。

标签: macos swiftui swiftui-texteditor


【解决方案1】:

行。所以代理绑定为我完成了这项工作。请参阅下面更新的编辑器视图:

struct ViewWithEditor: View {
  @Binding var entry: String
  var body: some View
  {
    let localString = Binding<String> (
      get: {
        entry
      },
      set: {
        entry = $0
      }
    )
    return VStack {
      Text(entry)
      TextEditor(text: localString)
    }
  }

有点难看(代理绑定看起来很混乱),但在某些方面更简单..

它允许编辑的结果在被推入绑定变量之前被审查/拒绝。

【讨论】:

    【解决方案2】:

    这是因为绑定条目 var 在 ViewWithEditor 初始化后实际上没有被使用。为了在不使用代理绑定的情况下完成这项工作,将 onChange 添加到 ViewWithEditor 中,如下所示:

    struct ViewWithEditor: View {
      @Binding var entry: String
      @State private var localString: String
    
      var body: some View
      {
        VStack {
          TextEditor(text: $localString)
        }
        .onChange(of: entry) {
            localString = $0
        }
      }
    
      init(entry: Binding<String>) {
        self._entry = entry
        self._localString = State(initialValue: entry.wrappedValue)
        print("init set local String to: (localString)")
      }
    }
    

    这里的问题是,如果 localString 更改,现在条目不会更新。人们可以使用与以前相同的方法:

      var body: some View
      {
        VStack {
          TextEditor(text: $localString)
        }
        .onChange(of: entry) {
            localString = $0
        }
        .onChange(of: localString) {
            entry = $0
        }
      }
    

    但为什么不直接使用 $entry 作为 TextEditor 的绑定字符串呢?

    【讨论】: