为什么使用预测输入多次调用shouldChangeTextInRange?

时间:2014-10-21 08:22:34

标签: objective-c ios8 uitextview

iOS8的预测输入多次调用UITextView的以下委托方法,导致所选单词多次插入到视图中。

此代码适用于键入单个字母和复制/粘贴,但不适用于使用预测输入栏时;为什么不呢?

- (BOOL) textView:(UITextView*)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text
{
    textView.text = [textView.text stringByReplacingCharactersInRange:range withString:text];
    return false;
}

使用此代码;如果我输入一个空的UITextView并点击""在预测文本(自动完成)视图中,它插入" The"通过对此方法进行三次调用进入视图。传递给每个调用的参数是:

  • 范围:{0,0}文字:@"The"
  • 范围:{0,0}文字:@"The"
  • 范围:{3,0}文字:@" "

我能理解的空间;但为什么插入""两次?

3 个答案:

答案 0 :(得分:16)

我遇到了同样的问题。看来,使用预测文本,在该委托方法中设置textView.text会再次触发对该委托方法的立即调用(据我所知,这只发生在预测文本中)。

我通过用一个警卫围绕我的textView更改来修复它:

private var hack_shouldIgnorePredictiveInput = false

func textView(textView: UITextView!, shouldChangeTextInRange range: NSRange, replacementText text: String!) -> Bool {
    if hack_shouldIgnorePredictiveInput {
        hack_shouldIgnorePredictiveInput = false
        return false
    }

    hack_shouldIgnorePredictiveInput = true

    textView.text = "" // Modify text however you need. This will cause shouldChangeTextInRange to be called again, but it will be ignored thanks to hack_shouldIgnorePredictiveInput

    hack_shouldIgnorePredictiveInput = false

    return false
}

答案 1 :(得分:1)

不是答案,而是更安全的解决方法:

class TextViewTextChangeChecker {
    private var timestamp: TimeInterval = 0
    private var lastRange: NSRange = NSRange(location: -1, length: 0)
    private var lastText: String = ""

    func shouldChange(text:String,in range: NSRange) -> Bool {
        let SOME_SHORT_TIME = 0.1
        let newStamp = Date().timeIntervalSince1970
        let same = lastText == text && range == lastRange && newStamp - timestamp < SOME_SHORT_TIME
        timestamp = newStamp
        lastRange = range
        lastText = text
        return !same
    }
}

这仍然没有帮助我,因为从shouldChangeTextInRange函数更改textView会将autocapitalizationType更改为.word(仅是通过行为,而不是字段本身)。

答案 2 :(得分:0)

我修改了理查德维纳布尔接受的答案,因为正如JLust在评论中指出的那样,第三次与空间的通话让我失望。

我添加了

private var predictiveTextWatcher = 0

并且

if predictiveTextWatcher == 1 {
            predictiveTextWatcher = 0
            return false
        }

        if hack_shouldIgnorePredictiveInput {
            predictiveTextWatcher += 1
            hack_shouldIgnorePredictiveInput = false
            return false
        }

这一切都很漂亮,但总比没有好。

最佳,