【发布时间】:2011-08-29 09:30:03
【问题描述】:
如何在可滚动、不可食用的 UITextView 中找到可见的文本?
例如我可能需要显示下一段,然后我想找到当前可见的文本范围并使用它来计算适当的范围并使用scrollRangeToVisible: 滚动文本视图
【问题讨论】:
标签: iphone ios uiscrollview uitextview
如何在可滚动、不可食用的 UITextView 中找到可见的文本?
例如我可能需要显示下一段,然后我想找到当前可见的文本范围并使用它来计算适当的范围并使用scrollRangeToVisible: 滚动文本视图
【问题讨论】:
标签: iphone ios uiscrollview uitextview
我在这里找到了另一个解决方案。 在我看来,这是解决这个问题的更好方法。 https://stackoverflow.com/a/9283311/889892
由于 UITextView 是 UIScrollView 的子类,它的 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]);
}
这假定一个从上到下、从左到右的文本布局。如果你想让它适用于其他布局方向,你将不得不更加努力。 :)
【讨论】:
我这样做的方法是计算每个段落的所有大小。用 sizeWithFont:constrainedToSize:lineBreakMode:
然后,您将能够从 [textView contentOffset] 确定哪个段落是可见的。
要滚动,不要使用 scrollRangeToVisible,只需使用 setContentOffset:CGPoint y 参数应该是下一段的所有高度大小的总和,或者只是添加 textView.frame.size.height,如果是的话比下一段的开头更接近。
这有意义吗?
回答下面的评论请求代码(未经测试):
CGFloat paragraphOffset[MAX_PARAGRAPHS];
CGSize constraint = CGSizeMake(widthOfTextView, 999999 /*arbitrarily large number*/);
NSInteger paragraphNo = 0;
CGFloat offset = 0;
for (NSString* paragraph in paragraphs) {
paragraphOffset[paragraphNo++] = offset;
CGSize paragraphSize = [paragraph sizeWithFont:textView.font constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
offset += paragraphSize.height;
}
// find visible paragraph
NSInteger visibleParagraph = 0;
while (paragraphOffset[visibleParagraph++] < textView.contentOffset.y);
// scroll to paragraph 6
[textView setContentOffset:CGPointMake(0, paragraphOffset[6]) animated:YES];
【讨论】:
如果你想要一个 Swift 解决方案,我使用这个:
斯威夫特 2
public extension UITextView {
public var visibleRange: NSRange? {
if let start = closestPositionToPoint(contentOffset) {
if let end = characterRangeAtPoint(CGPointMake(contentOffset.x + CGRectGetMaxX(bounds), contentOffset.y + CGRectGetMaxY(bounds)))?.end {
return NSMakeRange(offsetFromPosition(beginningOfDocument, toPosition: start), offsetFromPosition(start, toPosition: end))
}
}
return nil
}
}
斯威夫特 3
public extension UITextView {
public var visibleRange: NSRange? {
guard let start = closestPosition(to: contentOffset),
end = characterRange(at: CGPoint(x: contentOffset.x + bounds.maxX,
y: contentOffset.y + bounds.maxY))?.end
else { return nil }
return NSMakeRange(offset(from: beginningOfDocument, to: start), offset(from: start, to: end))
}
}
【讨论】:
您可以选择使用 UIWebView 而不是 UITextView。然后,您可以使用锚点和 javascript 滚动到文本中的适当位置。您可能可以在每个段落的开头以编程方式插入锚点以使其更容易。
【讨论】:
基于"Noodle of Death" answer的Swift 3.0/3.1解决方案。
public extension UITextView {
public var visibleRange: NSRange? {
if let start = closestPosition(to: contentOffset) {
if let end = characterRange(at: CGPoint(x: contentOffset.x + bounds.maxX, y: contentOffset.y + bounds.maxY))?.end {
return NSMakeRange(offset(from: beginningOfDocument, to: start), offset(from: start, to: end))
}
}
return nil
}
}
【讨论】: