UILabel sizeToFit не работает с autolayout ios6



как я должен настроить программно (и в каком методе) UILabel, высота которого зависит от его текста? Я пытался настроить его с помощью комбинации раскадровки и кода, но безрезультатно. Все рекомендуют sizeToFit при установке lineBreakMode и numberOfLines. Однако, независимо от того, если я положил этот код в viewDidLoad:,viewDidAppear: или viewDidLayoutSubviews Я не могу заставить его работать. Либо я делаю поле слишком маленьким для длинного текста, и оно не растет, либо я делаю его слишком большим, и это не так сокращаться.

689   13  

13 ответов:

обратите внимание что в большинстве случаев Мэтт!--5--> работает, как ожидалось. Но если это не работает для вас, пожалуйста, читайте дальше.

чтобы ваша метка автоматически изменяла высоту, вам нужно сделать следующее:

  1. установить ограничения макета для метки
  2. установить ограничение по высоте с низким приоритетом. Он должен быть ниже, чем ContentCompressionResistancePriority
  3. Set numberOfLines = 0
  4. Set ContentHuggingPriority выше, чем приоритет высоты метки
  5. установите preferredMaxLayoutWidth для метки. Это значение используется меткой для вычисления ее высоты

например:

self.descriptionLabel = [[UILabel alloc] init];
self.descriptionLabel.numberOfLines = 0;
self.descriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.descriptionLabel.preferredMaxLayoutWidth = 200;

[self.descriptionLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.descriptionLabel];

NSArray* constrs = [NSLayoutConstraint constraintsWithVisualFormat:@"|-8-[descriptionLabel_]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)];
[self addConstraints:constrs];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[descriptionLabel_]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];
[self.descriptionLabel addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[descriptionLabel_(220@300)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];

С Помощью Interface Builder

  1. установите четыре ограничения. Ограничение по высоте является обязательным. enter image description here

  2. затем перейдите в Инспектор атрибутов метки и установите количество строк в 0. enter image description here

  3. перейдите к инспектору размера метки и увеличьте вертикальное ContentHuggingPriority и вертикальное ContentCompressionResistancePriority.
    enter image description here

  4. выберите и измените ограничение высоты.
    enter image description here

  5. и уменьшить приоритет ограничения высоты.
    enter image description here

наслаждайтесь. :)

в iOS 6, используя autolayout, если стороны UILabel (или ширина) и верхняя часть закреплены, это будет автоматически расти и сжиматься вертикально, чтобы соответствовать его содержимому, с нет кода и не возиться с его сопротивлением сжатию или что-то еще. Это очень просто.

в более сложных случаях просто установите метку preferredMaxLayoutWidth.

в любом случае, правильно происходит автоматически.

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

первое, что нужно забыть sizeToFit. Авто макет будет обрабатывать это от вашего имени на основе внутреннего размера контента.

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

Итак, давайте начнем с примера UILabel, который имеет высоту, установленную в 41px high:

enter image description here

Как вы можете видеть на скриншот выше, "This is my text" имеет отступы сверху и снизу. Это заполнение между высотой UILabel, и это содержание, текст.

если мы запустим приложение в симуляторе, конечно же, мы увидим то же самое вещь:

enter image description here

теперь давайте выберем UILabel в Interface Builder и посмотрим на настройки по умолчанию в инспекторе размеров:

enter image description here

обратите внимание на выделенное выше ограничение. То есть Содержание Обнимать Приоритет. Как Эрика Садун описывает его в отличном iOS Auto Layout Demystified это:

то, как вид предпочитает избегать дополнительного заполнения вокруг его ядра содержание

для нас, с UILabel, основным содержанием является текст.

здесь мы подходим к сути этого базового сценария. Мы дали нашей текстовой метке два ограничения. Они конфликтуют. Один говорит:"высота должна быть равна 41 пикселей". Другой говорит:"обнимите вид на его содержание, чтобы у нас не было никаких дополнительных прокладок". В нашем случае обнимите вид на это текст так что у нас нет никаких дополнительных набивка.

теперь, с автоматической компоновкой, с двумя разными инструкциями, которые говорят, что делают разные вещи, среда выполнения должна выбрать один или другой. Он не может сделать и то, и другое. UILabel не может быть как 41 пикселей в высоту,и нет подклада.

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

Так что давайте попробуем. Мое ограничение по высоте имеет приоритет 1000, которая составляет требуются. Содержание обнимать высота 250, которая составляет слабый. Что произойдет, если мы уменьшим приоритет ограничения высоты до 249?

enter image description here

теперь мы можем видеть, что магия начинает происходить. Давайте попробуем в sim:

enter image description here

потрясающе! Содержание объятий достигнуто. Только потому, что приоритет высоты 249 меньше, чем содержание обнимать приоритет 250. В принципе, я говорю "высота, которую я указываю здесь, менее важна, чем то, что я указал для обнимания контента". Таким образом, содержание обниматься выигрывает.

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

оставит делать эквивалент для ширины в качестве упражнения для читателя!

заметил, что в iOS7 sizeToFit также не работает - возможно, решение может помочь вам тоже

[textView sizeToFit];
[textView layoutIfNeeded];

еще один вариант для обеспечения preferredMaxLayoutWidth метки хранится в синхронизации с шириной метки:

#import "MyLabel.h"

@implementation MyLabel

-(void)setBounds:(CGRect)bounds
{
    [super setBounds:bounds];

    // This appears to be needed for iOS 6 which doesn't seem to keep
    // label preferredMaxLayoutWidth in sync with its width, which 
    // means the label won't grow vertically to encompass its text if 
    // the label's width constraint changes.
    self.preferredMaxLayoutWidth = self.bounds.size.width;
}

@end

Я чувствую, что должен внести свой вклад, поскольку мне потребовалось некоторое время, чтобы найти правильное решение:

  • цель состоит в том, чтобы позволить Auto Layout делать свою работу, никогда не вызывая sizeToFit (), мы сделаем это, указав правильные ограничения:
  • укажите верхние, нижние и начальные/конечные ограничения пространства на вашем UILabel
  • установите свойство количество строк в 0
  • увеличить содержание обнимать приоритет до 1000
  • низкое сжатие контента Приоритет сопротивлением 500
  • в ограничении нижнего контейнера понизьте приоритет до 500

в основном, происходит то, что вы говорите своему UILabel, что, хотя он имеет фиксированное ограничение по высоте, он может нарушить ограничение, чтобы сделать себя меньше, чтобы обнять содержимое (если у вас есть одна строка, например), но он не может нарушить ограничение, чтобы сделать его больше.

в моем случае я создавал подкласс UIView, который содержал UILabel (неизвестной длины). В iOS7 код был прост: установите ограничения, не беспокойтесь о том, что контент обнимает или сопротивление сжатию, и все работало так, как ожидалось.

но в iOS6 UILabel всегда был привязан к одной строке. Ни один из ответов не работал для меня. Параметры обхвата содержимого и сопротивления сжатию были проигнорированы. Единственным решением, которое предотвратило отсечение, было включить a preferredMaxLayoutWidth на этикетке. Но я не знал, что установить предпочтительную ширину, так как размер его родительского вида был неизвестен (действительно, он будет определен содержимым).

Я, наконец, нашел решение здесь. Поскольку я работал над пользовательским представлением, я мог просто добавить следующий метод для установки предпочтительной ширины макета после того, как ограничения были вычислены один раз, а затем пересчитать их:

- (void)layoutSubviews
{
    // Autolayout hack required for iOS6
    [super layoutSubviews];
    self.bodyLabel.preferredMaxLayoutWidth = self.bodyLabel.frame.size.width;
    [super layoutSubviews];
}

Я решил с xCode6 положить "предпочтительную ширину" для автоматического и закрепить ярлык сверху, ведущий и замыкающий enter image description here

добавил UILabel программно и в моем случае этого было достаточно:

label.translatesAutoresizingMaskIntoConstraints = false
label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
label.numberOfLines = 0
UIFont *customFont = myLabel.font;
CGSize size = [trackerStr sizeWithFont:customFont
                             constrainedToSize:myLabel.frame.size // the size here should be the maximum size you want give to the label
                                 lineBreakMode:UILineBreakModeWordWrap];
float numberOfLines = size.height / customFont.lineHeight;
myLabel.numberOfLines = numberOfLines;
myLabel.frame = CGRectMake(258, 18, 224, (numberOfLines * customFont.lineHeight));

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

в любом случае, то, что сработало для меня, состояло в том, чтобы добавить необходимое ограничение высоты для UILabel и установить его вручную на правильную высоту при вызове intrinsicContentSize. Если у вас нет UILabel, содержащийся в другом UIView, вы можете попробовать подкласс UILabel и предоставить аналогичную реализацию, сначала установив ограничение высоты, а затем вернув
[super instrinsicContentSize]; вместо [self.containerview intrinsiceContentSize]; как я делаю ниже, что характерно для моего UIView подпространства.

- (CGSize)intrinsicContentSize
{
    CGRect expectedTextBounds = [self.titleLabel textRectForBounds:self.titleLabel.bounds limitedToNumberOfLines:1];
    self.titleLabelHeightConstraint.constant = expectedTextBounds.size.height;
    return [self.containerView intrinsicContentSize];

}

отлично работает теперь на iOS 7 и iOS 8.

решение, которое сработало для меня; если ваш UILabel имеет фиксированную ширину, измените ограничение с constant = до constant <= в файле интерфейс

enter image description here

в моем случае при использовании меток в UITableViewCell метка at будет изменяться, но высота будет превышать высоту ячейки таблицы. Это то, что сработало для меня. Я сделал в соответствии с Максом Маклеодом, а затем убедился, что высота ячейки была установлена на UITableViewAutomaticDimension.

вы можете добавить это в свой init или awakeFromNib,

self.tableView.rowHeight = UITableViewAutomaticDimension.  

в раскадровке выберите ячейку, откройте инспектор размеров и убедитесь, что высота строки установлена на "по умолчанию", установив флажок Флажок 'таможни'.

в 8.0 есть проблема, которая также требует, чтобы она была установлена в коде.

Comments

    Ничего не найдено.