如何在UITextView中有效地find可见词的CGRects?

我的目标是在UITextView中标记所有可见的拼写错误的单词。

效率低下的algorithm是使用拼写检查器来查找文本拼写错误的单词的所有范围,使用positionFromPosition:inDirection:offset等将它们转换为UITextRange对象,然后使用UITextInput方法firstRectFromRange获取graphics矩形。

因此,所有的文字 – >拼写错误的单词 – > NSRange集合 – > UITextRange集合 – > CGRect集合 – >评估可见性,绘制可见的

问题是这需要检查所有文本,并且所有拼写错误的单词都转换为graphics矩形。

因此,我想要走的路是以某种方式找出UITextView中底层.text的哪些部分是可见的。

因此,文本的可见范围 – >拼写错误的单词 – > NSRange集合 – > UITextRange集合 – > CGRect集合 – >评估可见性,绘制可见的

在iOS中的代码- 如何findUITextView中的文本的可见范围? 可能会作为一种方法来约束文本的哪些部分进行检查,但仍然要求所有的文本都是测量的,我想这可能是相当昂贵的。

有什么build议么?

由于UITextViewUIScrollView的子类,其bounds属性反映了其坐标系的可见部分。 所以这样的事情应该工作:

 - (NSRange)visibleRangeOfTextView:(UITextView *)textView { CGRect bounds = textView.bounds; UITextPosition *start = [textView characterRangeAtPoint:bounds.origin].start; UITextPosition *end = [textView characterRangeAtPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))].end; return NSMakeRange([textView offsetFromPosition:textView.beginningOfDocument toPosition:start], [textView offsetFromPosition:start toPosition:end]); } 

这假定从上到下,从左到右的文本布局。 如果你想使其适用于其他布局方向,你将不得不加倍努力。 🙂

Rob的回答,写在Swift中。 我已经添加了一些安全检查。

 private func visibleRangeOfTextView(textView: UITextView) -> NSRange { let bounds = textView.bounds let origin = CGPointMake(10,10) //Overcome the default UITextView left/top margin let startCharacterRange = textView.characterRangeAtPoint(origin) if startCharacterRange == nil { return NSMakeRange(0,0) } let startPosition = textView.characterRangeAtPoint(origin)!.start let endCharacterRange = textView.characterRangeAtPoint(CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))) if endCharacterRange == nil { return NSMakeRange(0,0) } let endPosition = textView.characterRangeAtPoint(CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds)))!.end let startIndex = textView.offsetFromPosition(textView.beginningOfDocument, toPosition: startPosition) let endIndex = textView.offsetFromPosition(startPosition, toPosition: endPosition) return NSMakeRange(startIndex, endIndex) } 

从button水龙头中调用的示例用法:

 @IBAction func buttonTapped(sender: AnyObject) { let range = visibleRangeOfTextView(self.textView) // Note: "as NSString" won't work correctly with Emoji and stuff, // see also: http://stackoverflow.com/a/24045156/1085556 let nsText = self.textView.text as NSString let text = nsText.substringWithRange(range) NSLog("range: \(range), text = \(text)") }