AutoLayout Динамический .xib Высота просмотра

Мне не удалось найти много возможностей AutoLayout с отдельными файлами .xib...

У меня есть автономный .xib файл, который имеет 3 представления - представление заголовка (которое содержит две метки), вход и нижний колонтитул (который содержит две кнопки). Это выглядит так:

enter image description here

Метки в виде заголовка имеют ограничения, которые должны влиять на вертикальный размер заголовка и, в свою очередь, размер всего представления. Подзаголовок - это метка с 0 строками, что означает, что она многострочная и динамическая. Все остальное имеет высоту набора с горизонтальными ограничениями для супервизора и верхних ограничений для сестры (или супервизора в случае просмотра заголовка).

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

Например, если я загружаю этот вид из .xib и устанавливаю его ширину до 300, как мне изменить размер его, чтобы разместить динамическую метку новой высоты? Нужно ли использовать метод intrinsicContentSize для определения этого размера?

Ответ 1

После долгих экспериментов и чтения я нашел ответ. Когда вы загружаете .xib в какой-то конструктор (в моем случае метод удобства на уровне класса), вы должны обязательно позвонить [view setTranslatesAutoresizingMaskIntoConstraints:NO]; Например, я сделал следующее:

+ (InputView *)inputViewWithHeader:(NSString *)header subHeader:(NSString *)subHeader inputValidation:(ValidationBlock)validation
{
    InputView *inputView = [[[NSBundle mainBundle] loadNibNamed:@"InputView" owner:self options:nil] lastObject];
    if ([inputView isKindOfClass:[InputView class]]) {
        [inputView setTranslatesAutoresizingMaskIntoConstraints:NO];
        [inputView configureWithHeader:header subHeader:subHeader inputValidation:validation];
        [inputView layoutIfNeeded];
        [inputView invalidateIntrinsicContentSize];
        return inputView;
    }
    return nil;
}

Затем необходимо переопределить layoutSubviews и intrinsicContentSize. Переопределение layoutSubviews позволяет мне установить preferredMaxLayoutWidth моей метки, в то время как переопределение intrinsicContentSize позволяет мне рассчитать размер, основанный на ограничениях и subviews! Вот моя реализация:

- (void)layoutSubviews {
    [super layoutSubviews];
    self.subHeaderLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
    [super layoutSubviews];
}

- (CGSize)intrinsicContentSize {
    CGFloat height = self.headerView.bounds.size.height;
    height += self.headerInputSpacer.constant;
    height += self.inputField.bounds.size.height;
    height += self.inputButtonSpacer.constant;
    height += self.buttonView.bounds.size.height;
    CGSize size = CGSizeMake([UIScreen mainScreen].bounds.size.width - 20, height);
    return size;
}

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

Ответ 2

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

Ответ 3

Это мой подход (версия Swift):

Вставить все внутри представления. Ваша иерархия xib должна быть:

  • Ваш xib
    • Вид
      • Все остальное, ваши ярлыки, кнопки и т.д.

Ограничение представления должно ограничивать верхние, ведущие и трейлингвированные (ваш xib), а внутри вашего "всего остального" должно быть ограничение нижнего уровня объекта viewview (View).

В вашем коде:

Загрузите нить

nib.frame.size.width = 80//Установите нужную ширину здесь

nib.label.text = "hello world" // Установите здесь свой динамический текст

nib.layoutIfNeeded()//Это будет вычислять и устанавливать высоты соответственно

nib.frame.size.height = nib.view.frame.height + 16//16 - общее количество верхнего зазора и нижнего зазора автомакета

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

Надеюсь, что это поможет.