Подтвердить что ты не робот

Правильное использование 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.

До тех пор, как вы считаете, самый чистый и самый правильный способ сделать именно то, что я показываю здесь, и полностью поддерживать автозапуск?

4b9b3361

Ответ 1

Я не думаю, что вам нужно определить intrinsicContentSize.

Вот две причины думать, что:

  • Когда в документации по автоматическому оформлению обсуждается intrinsicContentSize, она относится к ней как относящаяся к "листовым видам", например кнопкам или этикеткам, где размер может быть рассчитан исключительно на основе их содержимого. Идея состоит в том, что они являются листьями дерева дерева представлений, а не ветвей, потому что они не состоят из других представлений.

  • IntrinsicContentSize на самом деле не является "фундаментальной" концепцией в Auto Layout. Основные понятия - это просто ограничения и атрибуты, связанные ограничениями. ВнутреннийСодержаниеСодержание, приоритеты обнимания контента и приоритеты устойчивости к сжатию - это действительно просто удобство, которое можно использовать для создания внутренних ограничений, касающихся размера. Конечный размер - это результат того, что эти ограничения взаимодействуют со всеми другими ограничениями обычным способом.

И что? Поэтому, если ваш "пользовательский вид" - это просто сборка нескольких других представлений, тогда вам не нужно определять intrinsicContentSize. Вы можете просто определить ограничения, которые создают макет, который вы хотите, и эти ограничения также приведут к желаемому размеру.

В конкретном случае, который вы описываете, я установил ограничение на нижнее пространство >= 0 из метки в супервизор, другое из изображения в супервизор, а затем также ограничение с низким приоритетом нулевой высоты для в целом. Ограничение с низким приоритетом будет пытаться сжать сборку, в то время как другие ограничения перестанут ее сокращаться до тех пор, пока она не закроет свои подсмотры.

Если вы никогда не определяете intrinsicContentSize явно, как вы видите размер, связанный с этими ограничениями? Один из способов - заставить макет, а затем наблюдать результаты.

Другим способом является использование systemLayoutSizeFittingSize: (и в iOS8, малоизвестный systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:). Это более близкий родственник к sizeThatFits:, чем intrinsicContentSize. Это то, что система будет использовать для вычисления вашего подходящего размера, с учетом всех ограничений, которые он содержит, включая ограничения размера содержимого, а также все остальные.

К сожалению, если у вас многострочный ярлык, вам, вероятно, также потребуется настроить preferredMaxLayoutWidth, чтобы получить хороший результат, но эта другая история...