从NSRange创buildUITextRange

我需要在textview中查找不同范围的像素帧。 我正在使用- (CGRect)firstRectForRange:(UITextRange *)range; 去做吧。 但是我无法find如何实际创build一个UITextRange

基本上这就是我要找的:

 - (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView { UITextRange*range2 = [UITextRange rangeWithNSRange:range]; //DOES NOT EXIST CGRect rect = [textView firstRectForRange:range2]; return rect; } 

苹果说,为了采用UITextInput协议,我们必须UITextRangeUITextPosition 。 我不这样做,但我仍然试着按照文档的示例代码并将子类传递给导致崩溃的firstRectForRange

如果在textview中添加不同颜色的UILables更简单,请告诉我。 我曾尝试使用UIWebView的content editable设置为真,但我不喜欢与JS沟通,着色是我唯一需要的东西。

提前致谢。

您可以使用方法textRangeFromPosition:toPosition创build一个文本范围。 这种方法需要两个位置,所以你需要计算你的范围的开始和结束的位置。 这是通过positionFromPosition:offset方法完成的,它从另一个位置和一个字符偏移量中返回一个位置。

 - (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView { UITextPosition *beginning = textView.beginningOfDocument; UITextPosition *start = [textView positionFromPosition:beginning offset:range.location]; UITextPosition *end = [textView positionFromPosition:start offset:range.length]; UITextRange *textRange = [textView textRangeFromPosition:start toPosition:end]; CGRect rect = [textView firstRectForRange:textRange]; return [textView convertRect:rect fromView:textView.textInputView]; } 

这似乎有些荒谬,似乎是如此复杂。 一个简单的“解决方法”是select范围(接受NSRange),然后读取selectedTextRange(返回UITextRange):

 - (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView { textView.selectedRange = range; UITextRange *textRange = [textView selectedTextRange]; CGRect rect = [textView firstRectForRange:textRange]; return rect; } 

即使textView不是第一响应者,这也适用于我。


如果您不希望select持续,则可以重置selectedRange:

 textView.selectedRange = NSMakeRange(0, 0); 

…或保存当前的select并在之后恢复

 NSRange oldRange = textView.selectedRange; // do something // then check if the range is still valid and textView.selectedRange = oldRange; 

标题问题,这里是一个Swift 2扩展 ,从NSRange创build一个UITextRange。

UITextRange的唯一初始化工具是UITextInput协议上的一个实例方法,因此扩展还需要传入UITextInput,例如UITextFieldUITextView

 extension NSRange { func toTextRange(textInput textInput:UITextInput) -> UITextRange? { if let rangeStart = textInput.positionFromPosition(textInput.beginningOfDocument, offset: location), rangeEnd = textInput.positionFromPosition(rangeStart, offset: length) { return textInput.textRangeFromPosition(rangeStart, toPosition: rangeEnd) } return nil } } 

安德鲁·施赖伯的答案是易于复制/粘贴

 extension NSRange { func toTextRange(textInput:UITextInput) -> UITextRange? { if let rangeStart = textInput.position(from: textInput.beginningOfDocument, offset: location), let rangeEnd = textInput.position(from: rangeStart, offset: length) { return textInput.textRange(from: rangeStart, to: rangeEnd) } return nil } } 

这里是解释。

UITextRange对象表示文本容器中的一系列字符; 换句话说,它在支持文本input对象的string中标识开始索引和结束索引。

采用UITextInput协议的类必须创build自定义的UITextRange对象来表示由该类pipe理的文本内的范围。 范围的开始和结束索引由UITextPosition对象表示。 文本系统使用UITextRange和UITextPosition对象来传递文本布局信息。 有两个原因使用对象的文本范围,而不是原始types,如NSRange:

有些文档包含嵌套元素(例如,HTML标签和embedded​​对象),您需要跟踪可见文本中的绝对位置和位置。

iPhone文本系统所基于的WebKit框架要求文本索引和偏移量由对象表示。

如果您采用UITextInput协议,则必须创build一个自定义的UITextRange子类以及一个自定义的UITextPosition子类。

例如像在这些来源