
UITextView - один из наиболее часто используемых элементов в приложениях iOS. В основном, когда мы хотим позволить пользователям писать более длинные тексты, например. получать от них обратную связь.
Во многих проектах я встречал требование дизайнеров - иметь TextView, который автоматически адаптирует свою высоту к предоставленному контенту. К счастью, это довольно простая задача. Чтобы добиться этого, нам нужно начать с отключения прокрутки для текстового просмотра, просто установив:
textView.isScrollEnabled = false
Это даст автоматическому макету подсказку, что если он хочет отображать весь контент, ему нужно будет развернуть TextView. Второе требование - добавить некоторые ограничения, сообщающие нашему взгляду, в каком направлении ему разрешено расширяться. Например, мы можем прикрепить его к сторонам Top (), Left () и Right () родительского представления.
Так это выглядело бы как-то так:
self.view.addSubview(textView) textView.easy.layout(Left(10), Right(10), Top(200))
Примеры кода, которые я представляю в этой статье, выполнены с использованием EasyPeasy, фреймворка, который делает написание автоматической компоновки более прозрачным и более приятным для чтения.
Результатом вышеуказанных изменений являются следующие:

Вариант этой проблемы, который очень часто можно увидеть в StackOverflow, - это требование, которое связывает две функции TextView - его источник прокрутки и скорость реагирования на размер. Другими словами, часто просят расширить TextView до определенного размера после того, как он будет достигнут и пользователь предоставит больше контента - используйте прокрутку, чтобы позволить ему это сделать. Это может быть довольно сложно, поэтому давайте разделим его на основные шаги:
- Расширьте TextView до определенного размера - мы уже сделали это!
- По достижении - нам нужен способ измерить, какой размер поля у нас есть,
- И пользователь предоставляет больше контента - мы не хотим никоим образом блокировать ввод,
- Используйте прокрутку, чтобы позволить ему сделать это - так что нам нужно снова включить прокрутку.
Перейдем непосредственно к коду.
Как видите, мы добавили переменную isOversized с наблюдателем свойств didSet. Мы также назначили UITextViewDelegate, который позволяет нам действовать каждый раз, когда пользователь изменяет TextView.
Функциональность, помещенная в вызов textViewDidChange, представляет собой вычисление размера, используемого TextView, и проверку того, превышает ли он максимальную высоту, выбранную нами. Если это так - то мы присваиваем True значение is Oversized.
func textViewDidChange(_ textView: UITextView) {
if textView.contentSize.height >= maxHeight {
isOversized = true
}
}
Обратите внимание, что мы не присваиваем результат условия if напрямую, например:
isOversized = textView.contentSize.height >= maxHeight
в этом конкретном случае мы не хотим вызывать наблюдателя didSet при каждом изменении текста - мы ждем выполнения условия и только затем устанавливаем значение свойства.
Что касается didSet снова - textView.easy.reload () делает именно то, что он говорит - перезагружает ограничения. Он необходим для закрытия .when ({[unowned self] in self.isOversized}) для применения. Подробнее об этом можно прочитать здесь.
Результат кажется довольно приятным:

но у него есть одна вещь, которая все еще может быть лучше - после удаления некоторого содержимого textView остается на максимальной высоте. Чтобы улучшить это, нам нужно сделать несколько небольших настроек.
Сначала изменим textViewDidChange
func textViewDidChange(_ textView: UITextView) {
isOversized = textView.contentSize.height > maxHeight
}
Точно так же, как я написал выше, что это может быть не лучшая идея;)
Чтобы решить проблему с переопределенным наблюдателем, мы можем добавить охрану, проверяющую, изменилось ли значение:
Мы также добавили вызов setNeedsUpdateConstraints (). Это важно, потому что в противном случае textView может «пропустить» момент, когда ему нужно начать автоматически пересчитывать размер содержимого для отключенной прокрутки, что может привести к сжатию нашего TextView в одну строку до тех пор, пока пользователь не предоставит принудительное изменение текстового представления (добавив новую строку для пример).
Результат такой:

Надеюсь, что эта статья окажется для вас полезной или вы найдете одну недостающую строчку кода, которая мешала полному успеху :)
В следующей части мы попытаемся немного усложнить ситуацию и посмотрим, как управлять ситуациями, когда максимальный размер textView также должен быть динамическим, например, на экранах меньшего размера, когда мы отображаем экранную клавиатуру.