【问题标题】:SwiftUI UIViewRepresentable UITextView BindingSwiftUI UIViewRepresentable UITextView 绑定
【发布时间】:2020-05-07 11:23:57
【问题描述】:

SwiftUI 目前不支持多行文本输入(希望很快会添加此功能!)所以我一直在尝试使用组合框架从支持多行输入的 UIKit 实现 UITextView,但是我一直结果好坏参半。

这是我创建的用于制作文本视图的代码:

struct MultilineTextView: UIViewRepresentable {

    @Binding var text: String


    func makeUIView(context: Context) -> UITextView {
        let view = UITextView()
        view.isScrollEnabled = true
        view.isEditable = true
        view.isUserInteractionEnabled = true
        view.backgroundColor = UIColor.white
        view.textColor = UIColor.black
        view.font = UIFont.systemFont(ofSize: 17)
        view.delegate = context.coordinator
        return view
    }

    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = text
    }

    func frame(numLines: CGFloat) -> some View {
        let height = UIFont.systemFont(ofSize: 17).lineHeight * numLines
        return self.frame(height: height)
    }

    func makeCoordinator() -> MultilineTextView.Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UITextViewDelegate {
        var parent: MultilineTextView

        init(_ parent: MultilineTextView) {
            self.parent = parent
        }

        func textViewDidChange(_ textView: UITextView) {
            parent.text = textView.text
        }
    }
}

然后我在 swiftUI 视图中实现了它,例如:

MultilineTextView(text: title ? $currentItem.titleEnglish : $currentItem.pairArray[currentPair].english)//.frame(numLines: 4)

并将其绑定到状态变量:

@State var currentItem:Item

它有点工作。但是,状态 var currentItem:Item 包含一个字符串数组,然后我使用按钮循环遍历这些字符串,这些按钮根据输入到 MultilineTextView 中的内容更新字符串数组。这是我遇到的问题,MultilineTextView 似乎只绑定到数组中的第一个字符串项,然后它不会改变。当我使用 swiftUI 的本机 TextField 视图时,此功能可以正常工作,我可以循环遍历字符串数组并通过将文本输入到 TextField 来更新它。

我想我必须在 MultilineTextView 结构中遗漏一些东西才能允许此功能。任何指点都将不胜感激。

更新:添加了模型结构

struct Item: Identifiable, Codable {
    let id = UUID()
    var completed = false
    var pairArray:[TextPair]
}

struct TextPair: Identifiable, Codable {
    let id = UUID()
    var textOne:String
    var textTwo:String
}

编辑: 所以我做了更多的挖掘,我发现了我认为的问题。当 UITextView 的 textViewDidChange 被触发时,它会发送更新的文本,我可以在控制台中看到这些文本。奇怪的是,updateUIView 函数随后也会被触发,它会在通过 textViewDidChange 发送更新之前使用绑定 var 中的内容更新 UITextView 的文本。结果是 UITextview 在您输入时拒绝更改。奇怪的是,它对数组中的第一个 String 有效,但是当项目更改后,它就不再有效了。

【问题讨论】:

  • 您可能会发现我在How do I create a multiline TextField in SwiftUI?中提供的方法很有帮助
  • @Asperi,感谢提供了一个潜在的解决方案,但不幸的是,该代码仍然表现出相同的行为,它只会绑定到数组中的第一个文本实例,然后在状态时不允许任何输入它绑定的变量更改为数组中的另一项文本:/。烦人,因为它与本机 TextField 配合得很好。
  • 有趣...你能告诉我Item是什么吗?
  • 当然,它看起来像这样:``` struct Item: Identifiable, Codable { let id = UUID() var completed = false var pairArray:[TextPair] } struct TextPair: Identifiable, Codable { let id = UUID() var textOne:String var textTwo:String } ``` 对不起,如果帖子格式错误,我不知道如何在没有评论编辑器的情况下制作代码围栏。
  • @Asperi 感谢帖子的更新。澄清一下,这些项目存储在一个名为 ItemStore 的环境对象中,其中包含所有 Item 对象。

标签: swiftui combine


【解决方案1】:

SwiftUI 似乎为每个绑定创建了UIViewRepresentable 的两个变体,但在状态切换时不会切换它们,即title 切换......可能是由于缺陷,值得提交给Apple。

我找到了可行的解决方法(使用 Xcode 11.2 / iOS 13.2 测试),改为使用以下明确不同的视图

if title {
    MultilineTextView(text: $currentItem.titleEnglish)
} else {
    MultilineTextView(text: $currentItem.pairArray[currentPair].textOne)
}

【讨论】:

  • 感谢您的解决方案。它适用于标题,但不适用于pairArray。我愚蠢到没有说“currentPair”也是一个状态变量,这就是我的麻烦所在。请参阅下面的答案。
【解决方案2】:

所以我最终发现了问题,它没有更新的原因是因为我传入了一个包含两个状态变量的字符串。您可以看到,在下一行中,currentItem 是一个状态变量,而 currentPair 是另一个状态变量,它提供了一个索引号来定位字符串。后者没有被更新,因为它也没有通过绑定传递到多行文本视图中。

MultilineTextView(text: title ? $currentItem.titleEnglish : $currentItem.pairArray[currentPair].english)

我最初认为传入一个就可以了,而父视图将处理另一个,但事实并非如此。我通过创建两个绑定变量解决了我的问题,这样我就可以以动态方式找到我想要的字符串。现在听起来很愚蠢,但我当时看不到。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-13
    • 2020-03-23
    • 2022-01-18
    • 1970-01-01
    • 2020-05-09
    • 2022-01-22
    • 1970-01-01
    • 2022-12-23
    相关资源
    最近更新 更多