Правильное использование intrinsicContentSize и sizeThatFits: в подклассе UIView с автозапуском
Я прошу этот (каким-то образом) простой вопрос просто быть утонченным, потому что иногда меня беспокоит неправильное использование, которое я могу использовать для многих API UIView, особенно когда дело доходит до автозапуска.
Чтобы сделать его супер простым, я приведу пример, допустим, мне нужен подкласс UIView, у которого есть значок изображения и многострочная метка; поведение, которое я хочу, состоит в том, что высота моего представления изменяется с высотой метки (чтобы соответствовать тексту внутри), также я откладываю ее с помощью Interface Builder, поэтому у меня есть что-то вроде этого:
![simple view image]()
с некоторыми ограничениями, которые обеспечивают фиксированную ширину и высоту изображения, а также фиксированную ширину и положение (относительно изображения):
![simple view image, constraints shown]()
Теперь, если я устанавливаю какой-либо текст на метку, я хочу, чтобы представление было изменено по высоте, чтобы оно соответствовало ему, или осталось с той же высотой, что и в xib.
Перед автозапуском я бы всегда делал что-то вроде этого:
В файле подкласса CustoView я бы переопределил sizeThatFits:
следующим образом:
- (CGSize) sizeThatFits:(CGSize)size{
//this stands for whichever method I would have used
//to calculate the height needed to display the text based on the font
CGSize labelSize = [self.titleLabel intrinsicContentSize];
//check if we're bigger than what in ib, otherwise resize
CGFloat newHeight = (labelSize.height <= 21) ? 51: labelSize.height+20;
size.height = newHeight;
return size;
}
И чем я бы назвал что-то вроде:
myView.titleLabel.text = @"a big text to display that should be more than a line";
[myView sizeToFit];
Теперь, рассуждая о ограничениях, я знаю, что системы автоопределения вызывают intrinsicContentSize
в элементах дерева представлений, чтобы узнать, что их размер, и выполнить его вычисления, поэтому я должен переопределить intrinsicContentSize
в моем подпункте, чтобы вернуть то же самое он возвращается в ранее описанном методе sizeThatFits:
, за исключением того факта, что ранее при вызове sizeToFit
я правильно изменил свой вид, но теперь с автозапуском в сочетании с xib это не произойдет.
Конечно, я мог бы называть sizeToFit
каждый раз, когда редактирую текст в своем подклассе вместе с переопределенным intrinsicContentSize
, который возвращает тот же самый размер sizeThatFits:
, но почему-то я не думаю, что это правильно способ сделать это.
Я думал об переопределении needsUpdateConstraints
и updateConstraints
, но все же не имеет большого смысла, так как моя ширина и высота представления выводятся и переводятся из маски авторезистирования из xib.
До тех пор, как вы считаете, самый чистый и самый правильный способ сделать именно то, что я показываю здесь, и полностью поддерживать автозапуск?
Ответы
Ответ 1
Я не думаю, что вам нужно определить intrinsicContentSize.
Вот две причины думать, что:
-
Когда в документации по автоматическому оформлению обсуждается intrinsicContentSize
, она относится к ней как относящаяся к "листовым видам", например кнопкам или этикеткам, где размер может быть рассчитан исключительно на основе их содержимого. Идея состоит в том, что они являются листьями дерева дерева представлений, а не ветвей, потому что они не состоят из других представлений.
-
IntrinsicContentSize на самом деле не является "фундаментальной" концепцией в Auto Layout. Основные понятия - это просто ограничения и атрибуты, связанные ограничениями. ВнутреннийСодержаниеСодержание, приоритеты обнимания контента и приоритеты устойчивости к сжатию - это действительно просто удобство, которое можно использовать для создания внутренних ограничений, касающихся размера. Конечный размер - это результат того, что эти ограничения взаимодействуют со всеми другими ограничениями обычным способом.
И что? Поэтому, если ваш "пользовательский вид" - это просто сборка нескольких других представлений, тогда вам не нужно определять intrinsicContentSize. Вы можете просто определить ограничения, которые создают макет, который вы хотите, и эти ограничения также приведут к желаемому размеру.
В конкретном случае, который вы описываете, я установил ограничение на нижнее пространство >= 0 из метки в супервизор, другое из изображения в супервизор, а затем также ограничение с низким приоритетом нулевой высоты для в целом. Ограничение с низким приоритетом будет пытаться сжать сборку, в то время как другие ограничения перестанут ее сокращаться до тех пор, пока она не закроет свои подсмотры.
Если вы никогда не определяете intrinsicContentSize явно, как вы видите размер, связанный с этими ограничениями? Один из способов - заставить макет, а затем наблюдать результаты.
Другим способом является использование systemLayoutSizeFittingSize:
(и в iOS8, малоизвестный systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:
). Это более близкий родственник к sizeThatFits:
, чем intrinsicContentSize
. Это то, что система будет использовать для вычисления вашего подходящего размера, с учетом всех ограничений, которые он содержит, включая ограничения размера содержимого, а также все остальные.
К сожалению, если у вас многострочный ярлык, вам, вероятно, также потребуется настроить preferredMaxLayoutWidth
, чтобы получить хороший результат, но эта другая история...