Как принудительно расположить глифы далеко за пределами вертикальных границ UITextView?

Здесь код не нужен. Мне нужно некоторое руководство о том, как расположить все глифы очень длинной многострочной строки для отображения в UITextView с включенной прокруткой. Немного справочной информации для понимания обстоятельств.

Предыстория: у меня есть очень длинный многострочный текст, который необходимо представить в UITextView с включенной прокруткой. Я создал функцию, которая идентифицирует CGRect позицию совпадения строки поиска в многострочной строке, а затем переводит пользователя в CGRect позицию совпадения. Это достигается путем передачи CGRect совпадающего текста в contentOffset, который анимирует прокрутку до нужного места. CGRect, передаваемое в contentOffset, генерируется с использованием layoutmanager для обеспечения точности. Другими словами, CGRect текста основано на позиции глифа совпадающей строки.

Однако, если CGRect совпадающей строки поиска расположено вертикально далеко от UITextView bounds.height, анимация фактически не работает. Никакой прокрутки нет. Как будто анимация прокрутки не знает, где найти позицию CGRect для прокрутки до соответствующей строки. Я могу исправить проблему, если сначала вручную прокручу до самого низа UITextView, а затем выполню анимацию до позиции CGRect совпадающей строки поиска. При таких обстоятельствах создается впечатление, что UITextView имеет полное представление о макете текста и может точно найти расположение CGRect совпадающей строки поиска в многострочной строке.

Исходя из вышеизложенного, для меня очевидно, что UITextView не размещает сразу все глифы многострочной строки. Представление, вероятно, рисует глифы порциями, подобно тому, как табличное представление создает ячейки. Мне также кажется, что UITextView имеет возможность сохранять всю информацию о макете глифа, когда я вручную прокручиваю границы представления до самого низа вертикального размера содержимого.

Есть ли доступный код, который эффективно отображает весь размер содержимого UITextView, даже если глифы находятся далеко за пределами вертикальных границ UITextView? Похоже, мне нужно сначала расположить все глифы, чтобы предотвратить ошибку, описанную выше.


person KDiaz    schedule 11.04.2019    source источник
comment
Что не так с методом scrollRangeToVisible UITextView?   -  person rob mayoff    schedule 11.04.2019
comment
Роб: Да, scrollRangeToVisible знает, где найти совпадение. Однако функция имеет встроенную анимацию, которая конфликтует с анимацией, которую я запускаю. Я могу отключить встроенную анимацию scrollRangeToVisible. Есть проблема: моя анимационная последовательность также использует подпредставление, прямоугольник с границей размером с совпадающий текст. Подпредставление анимируется с помощью прокрутки и обводит совпадающий текст, чтобы служить визуальной подсказкой. Подпредставление использует CGRect глифа. Подвид тоже теряется. scrollRangeToVisible не предоставляет решения для определения местоположения подпредставления в правильном месте.   -  person KDiaz    schedule 11.04.2019
comment
Вы проверили, что текстовое представление contentSize достаточно велико, чтобы вместить ваше CGRect, прежде чем пытаться прокрутить? Возможно, contentSize не обновляется должным образом, если вы запускаете дополнительный добавочный макет вне контроля текстового представления.   -  person rob mayoff    schedule 11.04.2019
comment
Не напрямую. Я проверяю, находится ли прямоугольник последнего совпадения (я увеличиваю массив совпадений) в пределах текстового представления. Если false, то пользователь имеет возможность увеличивать массив совпадений, нажимая кнопку, которая запускает последовательность анимации, описанную выше. Короче говоря, анимация недоступна, если совпадение не находится за пределами текстового представления. Ошибка возникает, когда совпадающий текст находится на очень большом расстоянии от границ текстового представления.   -  person KDiaz    schedule 11.04.2019
comment
Роб: Когда я думаю о вашем предложении, каждый раз, когда я обращаюсь к contenSize, я получаю полный размер до запуска анимации. Должен быть какой-то объект, который можно обновить, чтобы предоставить необходимую информацию о макете. Как scrollRangeToVisible выполняет эту задачу?   -  person KDiaz    schedule 11.04.2019
comment
@KDiaz - вы заявляете, что используете layoutmanager для обеспечения точности ... используете ли вы функции .ensureLayout(..) и/или ensureGlyphs(...)?   -  person DonMag    schedule 12.04.2019
comment
DonMag.. Я использую let matchTxtRect = textView.layoutManager.boundingRect(forGlyphRange: matchRange, in: textView.textContainer), где textView — это объект UITextView, а matchRange — это значение NSRange, но только один элемент массива совпадающих диапазонов, найденных в многострочной строке.   -  person KDiaz    schedule 12.04.2019
comment
@KDiaz - непосредственно перед вызовом let matchTxtRect = textView.layoutManager.boundingRect(...) попробуйте позвонить textView.layoutManager.ensureLayout(for: textView.textContainer) --- если это не поможет, посмотрите другие доступные функции ensure: developer.apple.com/documentation/uikit/nslayoutmanager/   -  person DonMag    schedule 12.04.2019
comment
ДонМаг - Это помогло. Спасибо. Я поместил .ensureLayout в viewDidLayoutSubviews, который отлично работает. Медленно, но верно я начинаю лучше понимать объекты UIKit. -Кит   -  person KDiaz    schedule 15.04.2019
comment
@KDiaz - Рад, что это сработало для вас. Я добавил ответ с небольшим объяснением для всех, кто может столкнуться с этой проблемой в будущем.   -  person DonMag    schedule 15.04.2019


Ответы (1)


Из соображений производительности весь макет содержимого UITextView не обязательно определяется тогда, когда вы ожидаете.

Например, если у вас достаточно текста в текстовом представлении, чтобы охватить 10-кратную видимую область, UIKit может «отложить» размещение текста. В конце концов, только потому, что текст есть, это не значит, что пользователь когда-либо прокрутит его.

NSLayoutManager предоставляет несколько функций, которые позволяют вам убедиться, что все содержимое вашего текстового представления было размещено, когда вы хотите получить к нему доступ (см. https://developer.apple.com/documentation/uikit/nslayoutmanager):

func ensureGlyphs(forCharacterRange: NSRange)
func ensureGlyphs(forGlyphRange: NSRange)
func ensureLayout(forBoundingRect: CGRect, in: NSTextContainer)
func ensureLayout(forCharacterRange: NSRange)
func ensureLayout(forGlyphRange: NSRange)
func ensureLayout(for: NSTextContainer)

Согласно комментариям ОП, вызов .ensureLayout в viewDidLayoutSubviews() решил проблему.

person DonMag    schedule 15.04.2019
comment
DonMag... спасибо, что нашли время подумать над этим вопросом. Очень признателен. - person KDiaz; 16.04.2019