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

-systemLayoutSizeFittingSize: возвращает неправильную высоту для tableHeaderView под iOS 8

Существует множество потоков правильной калибровки tableHeaderView с автоматическим компоновкой (один такой поток), но они имеют тенденцию к предварительной версии iOS 8.

У меня есть ситуация с многочисленными табличными представлениями, все с заголовками, этот размер правильно под iOS 7, но неправильно под iOS 8, используя код, который больше всего назван выше. В контроллерах для таблиц у меня есть следующий метод:

- (void)rejiggerTableHeaderView
{
    self.tableView.tableHeaderView = nil;

    UIView *header = self.headerView;

    [header setNeedsLayout];
    [header layoutIfNeeded];

    CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    CGRect headerFrame = header.frame;
    headerFrame.size.height = height;

    header.frame = headerFrame;

    self.tableView.tableHeaderView = header;
}

С многострочной меткой в ​​iOS 7 это правильно упорядочивает заголовок таблицы так:

FQxFR0s.png

Но тот же код, выполняемый под iOS 8, производит следующее:

JOXLEsG.png

Какой трюк для получения -systemLayoutSizeFittingSize: вернуть правильный размер в iOS 8? Вот пример проекта, который демонстрирует проблему.

4b9b3361

Ответ 1

Изменение функции headerview для следующих работ для меня:

- (void)rejiggerTableHeaderView
{
    self.tableView.tableHeaderView = nil;

    UIView *header = self.headerView;
    CGRect frame = header.frame;
    frame.size.width = self.tableView.frame.size.width;
    header.frame = frame;

    [header setNeedsLayout];
    [header layoutIfNeeded];

    CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    CGRect headerFrame = header.frame;
    headerFrame.size.height = height;

    header.frame = headerFrame;

    self.tableView.tableHeaderView = header;
}

Ответ 2

Проблема может быть не установлена ​​preferredMaxLayoutWidth. Если вы установите его для коррекции ширины UILabel, он правильно определит ограничения.

Вы можете пройти через все UILabel в заголовке и установить preferredMaxLayoutWidth на ширину метки.

Пример Swift 3:

extension UITableView {
    public func relayoutTableHeaderView() {
        if let tableHeaderView = tableHeaderView {
            let labels = tableHeaderView.findViewsOfClass(viewClass: UILabel.self)
            for label in labels {
                label.preferredMaxLayoutWidth = label.frame.width
            }
            tableHeaderView.setNeedsLayout()
            tableHeaderView.layoutIfNeeded()
            tableHeaderView.frame.height = tableHeaderView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
            self.tableHeaderView = tableHeaderView
        }
    }

    public func findViewsOfClass<T:UIView>(viewClass: T.Type) -> [T] {
        var views: [T] = []
        for subview in subviews {
            if subview is T {
                views.append(subview as! T)
            }
            views.append(contentsOf: subview.findViewsOfClass(viewClass: T.self))
        }
        return views
    }
}

ОБНОВЛЕНИЕ 2:

Также у вас может возникнуть проблема с неправильным вычислением высоты, если у вас есть subview с ограничением соотношения сторон и в то же время пропорционально ограничению ширины супервизора

Ответ 3

Поскольку этот вопрос составляет полтора года, вот обновленная и полная версия в Swift. Некоторые из кода принятого ответа ошибочны или устарели.

func fixHeaderHeight() {
    // Set your label text if needed
    // ...
    //

    guard let header = tableView.tableHeaderView else {
        return
    }    
    let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    header.frame.height = height            
    tableView.tableHeaderView = header
}

В другом месте вашего кода вам нужно установить preferredMaxLayoutWidth метки (ов) в заголовке. Это должно быть равно tableView (или ширине экрана) за вычетом любого дополнения. Метод didSet вашей торговой марки - хорошее место:

@IBOutlet weak var headerMessageLabel: UILabel! {
        didSet {
            headerMessageLabel.preferredMaxLayoutWidth = UIScreen.mainScreen().bounds.width - headerMessageLabelPadding
        }
    }

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

Ответ 4

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

public extension UILabel {
    public class func size(withText text: String, forWidth width: CGFloat) -> CGSize {
        let measurementLabel = UILabel()
        measurementLabel.text = text
        measurementLabel.numberOfLines = 0
        measurementLabel.lineBreakMode = .byWordWrapping
        measurementLabel.translatesAutoresizingMaskIntoConstraints = false
        measurementLabel.widthAnchor.constraint(equalToConstant: width).isActive = true
        let size = measurementLabel.systemLayoutSizeFitting(UILayoutFittingCompressedSize)
        return size
    }
}

Примечание: приведенное выше в синтаксисе Swift 3.

При вычисленном выше size вы можете вернуть правильную высоту в методе UITableViewDelegate:

func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat

Ответ 5

Правильное решение этой проблемы в Swift 3 использует этот класс вместо стандартного UILabel:

class UILabelPreferedWidth : UILabel {
    override var bounds: CGRect {
        didSet {
            if (bounds.size.width != oldValue.size.width) {
                self.setNeedsUpdateConstraints()
            }
        }
    }

    override func updateConstraints() {
        if(preferredMaxLayoutWidth != bounds.size.width) {
            preferredMaxLayoutWidth = bounds.size.width
        }
        super.updateConstraints()
    }
}

Также убедитесь, что вы не отключили эти два в своем классе Cell:

translatesAutoresizingMaskIntoConstraints = false
contentView.translatesAutoresizingMaskIntoConstraints = false

Ответ 6

У меня была такая же проблема. Это хорошо работает для меня на iOS 8.4.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.myLabel sizeToFit];
    [self.tableView.tableHeaderView layoutIfNeeded];
    return UITableViewAutomaticDimension;
}