ios - как найти видимый диапазон текста в UITextView?
Как найти, какой текст виден в прокручиваемом, нередактируемом UITextView?
например, мне может понадобиться показать следующий абзац, затем я хочу найти текущий видимый текстовый диапазон и использовать его для вычисления соответствующего диапазона и использования scrollRangeToVisible:
прокрутить текстовое представление
5 ответов
Я бы сделал так, чтобы вычислить все размеры каждого абзаца. С sizeWithFont:constrainedToSize:lineBreakMode:
Затем вы сможете определить, какой абзац видим, из [textView contentOffset].
для прокрутки не используйте scrollRangeToVisible, просто используйте setContentOffset: параметр y CGPoint для этого должен быть либо суммой всех размеров высоты для следующего абзаца, либо просто добавить 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];
Я нахожу другое решение здесь. Это лучший способ решить эту проблему в моих глазах. /questions/11540873/kak-effektivno-najti-cgrects-dlya-vidimyih-slov-v-uitextview/11540875#11540875
Поскольку 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]);
}
Это предполагает макет текста сверху вниз, слева направо. Если вы хотите, чтобы он работал для других направлений компоновки, вам придется работать усерднее.:)
Если вы хотите решение Swift, я использую это:
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))
}
}
Решение 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
}
}
Один из вариантов - использовать UIWebView вместо UITextView. Затем вы можете использовать якоря и JavaScript, чтобы прокрутить до соответствующих мест в тексте. Возможно, вы можете вставить якоря программно в начале каждого абзаца, чтобы сделать это проще.