UITextView 委托 textViewDidChangeSelection 被调用两次

UITextView delegate textViewDidChangeSelection is called twice

我正在尝试在用户点击 Enter 按钮时做一些事情,所以我为 UITextView 实现了以下委托:

// Delegate is called when text is gonna change
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    if (text == "\n") {
        // Some behavior when user taps Enter
        return true
    }

    // Some other code
    return true
}

// Delegate is called when selection is changed
func textViewDidChangeSelection(_ textView: UITextView) {
    // Some code
}

问题是,当用户点击 Enter 时,textViewDidChangeSelection 被调用 两次

在第二次调用中,textView.selectedRange 被更改为文本视图的最后一个字符。当用户在文本中间的任何行之后点击 Enter 时,这会产生问题,因为插入符号位置更改为文本末尾。

我附上了一个可重现的例子here所以你可以检查,我不确定问题是在委托中,还是在我将委托附加到视图的方式中。

要重现问题,请执行以下场景:

  1. 写几行,例如:

    第 1 行。

    Bla bla bla

    第 3 行

  2. 转到第 1 行的末尾。

  3. 点击回车。

新行在正确的位置,但插入符号位置更改为文本视图的末尾。

备注:

好吧,我终于在 SwiftUI 的 UITextView 包装器中找到了这种奇怪的委托行为的解决方案。

所以整个问题是每次调用 updateUIView 时都要重新设置文本。这是没有必要的,它导致了一个奇怪的反馈循环 textViewDidChange 委托方法(这是我在最后一个字符为 \n 时设置所选范围的地方,换行就是这种情况)。

我不知道为什么会发生这种情况,我只是认为这是 UIViewRepresentables 背后工作方式的一个错误。

所以,为了解决这个问题,我不得不从 updateUIView 移动以下行:

uiView.text = document

并将其添加到 makeUIView:

textView.text = document

这样就永久绑定了