UITextView是否有文本更改的委托调用?

14

当我以编程方式设置我的 UITextView 如下:

[self.textView setText:@""];

委托方法 textViewDidChange: 不会被调用。 有没有一种方法可以找到它,而无需创建一个 UITextView 子类?


解决方案:https://dev59.com/IGw05IYBdhLWcg3w0VGa#59829100 - Fattie
insertText() 会调用 textViewDidChange - trndjc
7个回答

31

如果使用代码手动设置UITextView的文本内容,那么textViewDidChange:方法将不会被调用。(但是,如果你设置了你的文本视图的delegate,当用户编辑它时它将被调用。)

一种可能的解决方法是在编辑文本时手动调用textViewDidChange:方法。例如:

[self.textView setText:@""];
[self textViewDidChange:self.textView];

这种做法有点取巧,但它能够完成任务。


这是一个有趣的方法。大多数人不考虑手动调用框架的委托方法。然而,这是一个好主意。 - Onur Tuna
在我看来,绝对不是hackish。方法就是用来调用的,而这个方法正好摆在你面前。 - trndjc
我认为使用[self.textView.delegate textViewDidChange:self.textView]更安全,以防delegate更改为不同于self的对象。 - Iulian Onofrei

9
我赞同@rebello95的回答,因为这是一种方法。但另一种不那么hacky的方法是按照以下方式进行操作:
- (void)whereIManuallyChangeTextView
{//you don't actually have to create this method. It's simply wherever you are setting the textview to empty
  [self.textView setText:@""];
  [self respondToChangeInTextView:self.textView];
}
    
- (void)textViewDidChange:(UITextView *)textView
{
  //...some work and then
  [self respondToChangeInTextView:textView];
}
    
- (void)respondToChangeInTextView:(UITextView *)textView
{
  //what you want to happen when you programmatically/manually or interactively change the textview
}

这段代码展示了一种值得推荐的编程模式,可以让你的代码更易读。

4

在Swift中,您可以重写UITextView类的text变量:

class MyTextView: UITextView {

    override public var text: String? {
        didSet {
            self.textViewDidChange(self)
        }
    }

}

这不起作用,因为当用户输入时它没有被调用。 - Lucas Chwe
1
它应该只是增强TextView,以便在通过代码更改文本时调用委托。@LucasChwe - linus_hologram

2

虽然这是一个旧帖子,但我也遇到了同样的问题,所以我想分享一下我的解决方案(使用Swift)。

textViewDidChange(_ textView: UITextView)通过设置文本属性不会被调用,但是当使用replace(range: UITextRange, withText: String)时它就会被调用。因此,您需要为UITextView的整个字符串创建一个UITextRange,并用新字符串替换它。

// Create a range of entire string
let textRange = textView.textRange(from: textView.beginningOfDocument, to: textView.endOfDocument)
// Create a new string
let newText = ""
// Call Replace the string in your textView with the new string
textView.replace(textRange!, withText: newText)

那就这样吧。当然,为了使它起作用,您需要设置UITextViewDelegate:
class ViewController: UIViewController, UITextViewDelegate {

1
我尝试过这个,但是使用textView.replace对我来说没有调用委托。 - HixField

0

委托方法textDidChange无法响应文本的编程更改,您可以使用观察来获得通知。

  1. 使用@objc dynamic声明您的文本视图变量。
  2. 声明并持有一个类型为NSKeyValueObservation的变量。
  3. 使用函数observe(_:changeHandler:)绑定您的文本视图的文本属性,并将返回值与步骤2中声明的变量一起保存。
  4. changeHandler中观察更改。

示例:

@objc dynamic private var textView: UITextView!
private var observation: NSKeyValueObservation?

func bind() {
    observation = observe(\.textView.text, options: [.old, .new]) { object, change in
        print(object, change)
    }
}

0
你也可以继承UITextView并重写setText方法,包括

[self textViewDidChange:self.textView]

这样你就不必每次设置UITextView文本时都调用它了。

-1
使用这个代替:(这不会重置当前文本)

[self.textView insertText:@"something"];

这将调用委托并在光标所在位置添加文本。当然,如果您想重置整个文本,可以执行以下操作:

[self.textView setText:@""];
[self textViewDidChange:self.textView];

或者

[self.textView setText:@""];
[self.textView insertText:@"something"];

insertText不会调用委托。 另外:"textViewDidChange: 讨论文本视图在响应用户对文本所做的更改时调用此方法。该方法不会在响应于程序化发起的更改时被调用。" 来自:https://developer.apple.com/reference/uikit/uitextviewdelegate#jumpTo_7 - OhadM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接