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

Autolayout добавляет дополнительную прокладку сверху и снизу UILabel iPhone 6/6 +, если выбрана опция MaxLayoutWidth

Я создал образец проекта, чтобы воспроизвести это.

У меня есть xib файл с UILabel с фиксированным верхним, ведущим и конечным ограничениями. Я добавил ограничение minHeight и установил количество строк в 0.

Я устанавливаю для preferredMaxLayoutWidth значение Automatic (проверяется в файле xib).

В viewDidLoad у меня есть это:

self.myLabel.layer.borderColor = [[UIColor redColor] CGColor];
self.myLabel.layer.borderWidth = 2.0f;
self.myLabel.text = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

И когда я запускаю симулятор на iPhone 6 или 6+, я получаю следующее:

enter image description here

Я понятия не имею, откуда идет верхнее и нижнее дополнение, и оно пропорционально количеству символов в UILabel.

Есть ли какие-то магические настройки, которые я забыл? Он отлично работает на устройствах iPhone 4.

Теперь, если я не устанавливаю предпочтительныйMaxLayoutWidth, у него нет дополнительного дополнения, но это прерывает мои многострочные строки в UILabel. Он отсекает текст. Я не использовал Size-Class.

Edit:

Таким образом, я изменил несколько вещей в своем примере проекта, чтобы соответствовать ситуации в моем реальном проекте. Я добавил tableView (с верхними, ведущими, нижними и конечными ограничениями, установленными в его родительском представлении). Каждая ячейка таблицыView имеет 4 метки. Верхняя метка имеет верхнее, ведущее и конечное ограничение для contentView ячейки, а последующие метки имеют вертикальное ограничение над надписью над ней. Каждая метка имеет набор ограничений heightGreaterThan и набор widthGreaterThan.

Это выглядит так, как если бы не выбран предпочтительный наборMaxLayoutWidth (обратите внимание, как метки ограничены до 1 строки). No preferredMaxLayoutWidth

С предпочтительнымMaxLayoutWidth. Теперь UILabel показывает весь контент, но имеет дополнение сверху и снизу. With preferredMaxLayoutWidth but with top and bottom padding

Edit2: Пример проекта: https://www.dropbox.com/s/sdahx9njnsxiv98/MultiLineUILabel.zip?dl=1

4b9b3361

Ответ 1

Итак, что я закончил делать, это создать подкласс для метки и переопределить setBounds: и установить предпочтительныйMaxLayoutWidth для своих границ.

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

    if (self.preferredMaxLayoutWidth != bounds.size.width) {
        self.preferredMaxLayoutWidth = bounds.size.width;
        [self setNeedsUpdateConstraints];
}}

Кроме того, в подклассе UITableViewCell я переопределяю layoutSubiews

- (void)layoutSubviews {
    [super layoutSubviews];

    [self.contentView layoutIfNeeded];

    // labelsCollection is an IBOutletCollection of my UILabel sublasses
    for (UILabel *label in self.labelsCollection) {
        label.preferredMaxLayoutWidth = label.bounds.size.width;
}}

Это работает все время. Я думаю, что причиной этого нечетного поведения является то, что UILabel изначально устанавливается на 280px (320px - padding с обеих сторон) в файле xib, но во время выполнения он меняет свою ширину, чтобы разместить большие экраны (поскольку я устанавливаю ведущую и конечную ограничений увеличивает ширину, которая меняет "preferredMaxLayoutWidth" на большее значение). По какой-то причине UILabel не обновляет свой предпочтительныйMaxLayoutWidth до большего значения и вызывает белое пространство сверху и снизу.

Это моя гипотеза.

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

Ответ 2

Любой, кто изучает этот вопрос, который уже использует maxPreferredLayoutWidth (кстати, у вас нет подкласса, просто установите это в viewDidLayoutSubviews вашего VC) проверьте, что вы устанавливаете его в ширину правильного вида.

Шахта не работала, потому что у меня было:

label1.maxPreferredLayoutWidth = label1.frame.width
label2.maxPreferredLayoutWidth = label1.frame.width

Когда это должно было быть:

label1.maxPreferredLayoutWidth = label1.frame.width
label2.maxPreferredLayoutWidth = label2.frame.width

Вы видите разницу? Я не 3 часа lol

Ответ 3

используя этот класс, он исправил его для меня

import UIKit

class CustomLabel: UILabel {

    override func drawText(in rect: CGRect) {
        if let stringText = text {
            let stringTextAsNSString = stringText as NSString
            let labelStringSize = stringTextAsNSString.boundingRect(with: CGSize(width: self.frame.width, height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil).size
            super.drawText(in: CGRect(x: 0, y: 0, width: self.frame.width, height: ceil(labelStringSize.height)))
        } else {
            super.drawText(in: rect)
        }
    }

}

Ответ 4

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

Вместо этого вы можете использовать не редактируемый UITextView с UIViewContentModeTop.

Ответ 5

Есть ли какое-либо ограничение в нижней части метки? Я считаю, что это позволяет растягиваться из-за приоритета обхода контента. Установите его на 1000 (обязательно). Это предотвратит его расширение за пределы его размера текста. Затем вам нужно будет добавить соответствующие ограничения для нижней части метки.

Ответ 6

Поскольку мне нужно было установить preferredMaxLayoutWidth для совместимости с iOS 7, я в итоге позвонил boundingRectWithSize, чтобы вычислить требуемую высоту ярлыка и установить постоянную константу ограничения высоты для UILabel.

CGRect labelRect = CGRectIntegral([myText boundingRectWithSize:size 
    options:options attributes:attributes context:context]);
self.myLabelHeightConstraint.constant = labelRect.size.height;

Ответ 7

Так вот как я реализовал это на быстрых, В классе, расширяющем UILabel, я переопределяю границы var с помощью getter и setter, который устанавливает суперграницы var и возвращает его, таким образом вы можете добавить некоторый код в get и set.

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

    override var bounds:CGRect {
        get {
            return super.bounds
        }
        set {
            super.bounds = newValue
            if (self.preferredMaxLayoutWidth != super.bounds.size.width) {
                self.preferredMaxLayoutWidth = super.bounds.size.width;
                self.setNeedsUpdateConstraints()
            }
        }
    }

Ответ 8

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

Я столкнулся с этой проблемой в некоторых моих проектах. Поэтому мое решение исправить это:

  • В ячейке у меня есть следующий способ настройки: - (void) configureWithSomeObject: parentViewSize: и в tableView: cellForRowAtIndexPath: я создал такую ​​ячейку:

    - (UITableViewCell *)tableView:(UITableView *)tableView  cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    YourCell *cell;
    
    //cell initialization
    
    [cell configureWithSomeObject:nil parentViewSize:tableView.frame.size];
    
    return cell;
    }
    
  • Внутренние методы настройки просто устанавливают preferredMaxLayoutWidth в соответствии с шириной родителя:

     - (void)configureWithSomeObject:(NSObject)someObject parentViewSize:(CGSize)parentViewSize {
    // do your stuff
    
    self.someLabel.preferredMaxLayoutWidth = parentViewSize.width;
     }
    

P.S. в случае, если у вас есть ведущие/конечные пробелы, вы должны вычесть его из значения parentViewSize.width.

Надеюсь, это будет полезно для любого:)

Ответ 9

У меня была аналогичная проблема, и просто подклассификация UILabel и переопределения setBounds не работала для меня. При переходе через setBounds я заметил, что высота метки была 39.999999993. Поэтому я сделал следующее изменение, чтобы округлить его до 40:

- (void)setBounds:(CGRect)bounds
{
    bounds.size.height = ceilf(CGRectGetHeight(bounds));

    [super setBounds: bounds];

    if (self.preferredMaxLayoutWidth != bounds.size.width)
    {
        self.preferredMaxLayoutWidth = bounds.size.width;
        [self setNeedsUpdateConstraints];
    }
}

Это фиксировало это для меня, больше дополнительных надписей выше и ниже моего UILabel на больших устройствах. Я также не должен был устанавливать приоритет обхода контента.