-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? Вот пример проекта, который демонстрирует проблему.
Ответы
Ответ 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;
}