Набивання UILabel
, повне рішення. Оновлено до 2020 року.
Виявляється, три речі треба зробити.
1. Необхідно зателефонувати textRect # forBounds з новим меншим розміром
2. Необхідно переосмислити малюнокText новим меншим розміром
3. Якщо комірка з динамічним розміром, повинна налаштувати intrinsicContentSize
У типовому прикладі, наведеному нижче, текстовий блок знаходиться у вигляді таблиці, подання стека чи подібної конструкції, що надає йому фіксовану ширину . У прикладі ми хочемо набивання 60,20,20,24.
Таким чином, ми беремо "існуючий" intrinsicContentSize і фактично додаємо 80 до висоти .
Повторювати ...
Ви повинні буквально "отримати" висоту, обчислену "поки що" двигуном, і змінити це значення.
Я вважаю цей процес заплутаним, але саме так він працює. Для мене Apple повинна викласти дзвінок під назвою "на кшталт" попередній розрахунок висоти ".
По-друге, ми повинні фактично використовувати виклик textRect # forBounds з нашим новим меншим розміром .
Отже, у textRect # forBounds ми спочатку робимо розмір меншим, а потім називаємо супер.
Попередження! Ви повинні зателефонувати супер після , а не раніше!
Якщо ви ретельно досліджуєте всі спроби та обговорення на цій сторінці, це саме проблема. Помітьте, що деякі рішення "здаються майже працюючими", але тоді хтось повідомить, що в певних ситуаціях це не вийде. Це дійсно точна причина - заплутано потрібно "зателефонувати супер після цього", а не раніше.
Отже, якщо ви називаєте супер це "в неправильному порядку", воно зазвичай працює, але не для певної довжини тексту .
Ось точний наочний приклад "неправильно робити супер першим":
Зауважте, правильність 60,20,20,24, але обчислення розміру насправді невірно, оскільки це було зроблено за схемою "супер перший" у textRect # forBounds.
Виправлено:
Зауважте, що лише зараз движок textRect # forBounds знає, як правильно зробити обчислення :
Нарешті!
Знову ж таки, у цьому прикладі UILabel використовується в типовій ситуації, коли фіксується ширина. Отже, в intrinsicContentSize ми повинні "додати" загальну додаткову висоту, яку ми хочемо. (Вам не потрібно жодним чином "додавати" ширину, це було б безглуздо, як це визначено.)
Потім у textRect # forBounds ви отримуєте межі, "запропоновані поки що", шляхом авторозмітки, ви віднімаєте свої поля, і лише потім знову зателефонуєте до двигуна textRect # forBounds, тобто в супер, що дасть результат.
Нарешті і просто в малюнку. Ви, звичайно, малюєте в тому ж меншому полі.
Фу!
let UIEI = UIEdgeInsets(top: 60, left: 20, bottom: 20, right: 24) // as desired
override var intrinsicContentSize:CGSize {
numberOfLines = 0 // don't forget!
var s = super.intrinsicContentSize
s.height = s.height + UIEI.top + UIEI.bottom
s.width = s.width + UIEI.left + UIEI.right
return s
}
override func drawText(in rect:CGRect) {
let r = rect.inset(by: UIEI)
super.drawText(in: r)
}
override func textRect(forBounds bounds:CGRect,
limitedToNumberOfLines n:Int) -> CGRect {
let b = bounds
let tr = b.inset(by: UIEI)
let ctr = super.textRect(forBounds: tr, limitedToNumberOfLines: 0)
// that line of code MUST be LAST in this function, NOT first
return ctr
}
Знову. Зауважте, що відповіді на це та інші питання якості, які є "майже" правильними, зазнають проблеми на першому зображенні вище - "супер не в тому місці" . Ви повинні змусити розмір більше в intrinsicContentSize, а потім у textRect # forBounds спочатку потрібно скоротити межі першої пропозиції, а потім викликати супер.
Підсумок: ви повинні "зателефонувати супер останньою " у textRect # forBounds
У цьому секрет.
Зверніть увагу, що вам не потрібно і не потрібно додатково викликати недійсний, sizeThatFits, needsLayout або будь-який інший примусовий виклик. Правильне рішення повинно працювати належним чином у звичайному циклі витягнення автомашини.
Порада:
Якщо ви працюєте з шрифтами Monospace, ось чудова порада: https://stackoverflow.com/a/59813420/294884