Высота заголовка таблицы неверна при использовании автоматического макета, IB и размеров шрифтов
Я пытаюсь создать представление заголовка для моего uiTableView (не заголовок раздела, у меня уже есть). Я установил XIB в построителе интерфейса. Все соединения подключены и прекрасно работают... кроме стола не хватит места! Моя проблема в том, что верхняя часть таблицы немного перекрывает заголовок таблицы.
Мой XIB настроен с автозапуском для всех кнопок, и IB рада, что ограничения не конфликтуют/неоднозначны. В представлении установлен размер Freeform, который в моем случае оказался 320 x 471. Тогда в ограничениях для представления я установил собственный размер для представления того же самого.
Теперь это отлично работает с моей таблицей. Все выглядит великолепно. Но если я вручную изменю любой из шрифтов в представлении заголовка с кодом, макет сделает вид больше, и он окажется под моей таблицей.
Любые идеи о том, как заставить tableviewcontroller оставлять достаточно места для просмотра заголовка после установки шрифтов и размеров? Надеюсь, у меня есть смысл объяснить это.
Ответы
Ответ 1
Идея состоит в том, чтобы рассчитать высоту заголовка с помощью systemLayoutSizeFittingSize:targetSize
.
Возвращает размер представления, который удовлетворяет ограничениям, которые он имеет. Определяет наилучший размер представления с учетом всех ограничений и т.д. его подзонов.
После изменения высоты заголовка необходимо переназначить свойство tableHeaderView
для настройки ячеек таблицы.
На основе этого ответа: Использование автоматической компоновки в UITableView для динамических раскладок ячеек и высоты строк в строке
- (void)sizeHeaderToFit
{
UIView *header = self.tableView.tableHeaderView;
[header setNeedsLayout];
[header layoutIfNeeded];
CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
CGRect frame = header.frame;
frame.size.height = height;
header.frame = frame;
self.tableView.tableHeaderView = header;
}
Ответ 2
У меня возникла аналогичная проблема, когда я пытался установить заголовок таблицы в пользовательский вид, который я определил с помощью автоматического макета, используя конструктор интерфейса.
Когда я это сделал, я обнаружил, что он будет закрыт заголовком раздела.
Моя работа включала использование "фиктивного представления" в качестве представления заголовка таблицы, а затем добавление моего настраиваемого представления к этому фиктивному представлению в качестве подчиненного. Я думаю, что это позволяет авто макету настраивать внешний вид в соответствии с ограничениями и содержащим рамкой представления. Это, вероятно, не так элегантно, как решение vokilam, но оно работает для меня.
CGRect headerFrame = CGRectMake(0, 0, yourWidth, yourHeight);
UIView *tempView = [[UIView alloc] initWithFrame:headerFrame];
[tempView setBackgroundColor:[UIColor clearColor]];
YourCustomView *customView = [[YourCustomView alloc] initWithFrame: headerFrame];
[tempView addSubview:movieHeader];
self.tableView.tableHeaderView = tempView;
Ответ 3
Поскольку ваш tableHeaderView
представляет собой введенную форму xib
с автоматическим макетом, поэтому ограничения ваших пользовательских headerView
и superView
неизвестны. Вы должны добавить constraints
своего пользовательского headerView
:
1.in viewDidLLoad
назначьте свой пользовательский заголовочный файл tableView tableHeaderView
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *yourHeaderView = [[[NSBundle mainBundle] loadNibNamed:@"yourHeaderView" owner:nil options:nil] objectAtIndex:0];
//important:turn off the translatesAutoresizingMaskIntoConstraints;apple documents for details
yourHeaderView.translatesAutoresizingMaskIntoConstraints = NO;
self.tableView.tableHeaderView = yourHeaderView;
}
2.in - (void) updateViewConstraints, добавьте существенные ограничения вашего настраиваемого headerView
- (void)updateViewConstraints
{
NSDictionary *viewsDictionary = @{@"headerView":yourHeaderView};
NSArray *constraint_V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[headerView(121)]"
options:0
metrics:nil
views:viewsDictionary];
NSArray *constraint_H = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[headerView(320)]"
options:0
metrics:nil
views:viewsDictionary];
[self.headerView addConstraints:constraint_H];
[self.headerView addConstraints:constraint_V];
NSArray *constraint_POS_V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[headerView]"
options:0
metrics:nil
views:viewsDictionary];
NSArray *constraint_POS_H = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[headerView]"
options:0
metrics:nil
views:viewsDictionary];
[self.tableView addConstraints:constraint_POS_V];
[self.tableView addConstraints:constraint_POS_H];
[super updateViewConstraints];
}
OK!
PS: Вот связанный документ: Изменение размеров представлений диспетчера просмотров
Ответ 4
Что я решил решить эту проблему:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
sizeHeaderToFit()
}
private func sizeHeaderToFit() {
if let headerView = tableView.tableHeaderView {
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
var newFrame = headerView.frame
// Needed or we will stay in viewDidLayoutSubviews() forever
if height != newFrame.size.height {
newFrame.size.height = height
headerView.frame = newFrame
tableView.tableHeaderView = headerView
}
}
}
Я нашел это решение где-то и работал как шарм, я не могу вспомнить, где.
Ответ 5
Я нашел вокилама, чтобы работать отлично. Здесь его решение в Свифт.
func sizeHeaderToFit() {
guard let header = tableView.tableHeaderView else { return }
header.setNeedsLayout()
header.layoutIfNeeded()
let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
header.frame.size.height = height
tableView.tableHeaderView = header
}
Ответ 6
В моем случае systemLayoutSizeFittingSize
возвращает неправильный размер, потому что в одном из подзонов используется соотношение сторон (ширина к высоте) 4: 1.
После того, как я изменил его на значение ограничения константы (100), он начнет работать как ожидалось.
Ответ 7
Объединение ответов с помощью @SwiftArchitect, @vokilam и @mayqiyue и использование программно созданного tableHeaderView
вместо nib (хотя, я не вижу причин, почему он не должен работать с nib), и под iOS 10.x/Xcode 8.2.1, вот что я работаю:
Создайте представление в вашем контроллере представления -viewDidLoad
или - init
или везде, где вы используете представление таблицы:
MyCustomTableHeaderView *myCustomTableHeaderView = [[MyCustomTableHeaderView alloc] init]; // Don't set its frame
myCustomTableHeaderView.translatesAutoresizingMaskIntoConstraints = NO;
self.myTableView.tableHeaderView = myCustomTableHeaderView;
self.myCustomTableHeaderView = myCustomTableHeaderView; // We set and update our constraints in separate methods so we store the table header view in a UIView property to access it later
В тех случаях, когда вы настраиваете свои собственные ограничения вида заголовка (может быть в `updateConstraints, но этот метод можно вызвать несколько раз):
// We use Pure Layout in our project, but the workflow is the same:
// Set width and height constraints on your custom view then pin it to the top and left of the table view
// Could also use VFL or NSLayoutConstraint methods
[self.myCustomTableHeaderView autoSetDimension:ALDimensionWidth toSize:CGRectGetWidth(self.superview.frame)]; // Width set to tableview width
[self.myCustomTableHeaderView autoSetDimension:ALDimensionHeight toSize:height]; // Whatever you want your height to be
[self.myCustomTableHeaderView autoPinEdgeToSuperviewEdge:ALEdgeTop];
[self.myCustomTableHeaderView autoPinEdgeToSuperviewEdge:ALEdgeLeft];
// This is important
[self.myCustomTableHeaderView layoutIfNeeded]; // We didn't need to call -setNeedsLayout or reassign our custom header view to the table view tableHeaderView property again, as was noted in other answers
Ответ 8
Другие ответы указали мне в правильном направлении для правильного изменения размера таблицыHeaderView. Тем не менее, я получал промежуток между заголовком и ячейками tableView. Это также может привести к тому, что ваши ячейки будут перекрываться с вашим заголовком, в зависимости от того, увеличивается или уменьшится заголовок.
Я пошел от этого:
tableView.reloadData()
let height = tableViewHeader.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
tableView.tableHeaderView?.frame.size.height = height
Чтобы устранить пробел/перекрытие, мне пришлось только перемещать tableView.reloadData() после того, как я установил новую высоту, а не ранее.
Для этого:
let height = tableViewHeader.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
tableView.tableHeaderView?.frame.size.height = height
tableView.reloadData()
Ответ 9
sizeHeaderToFit
, предложенный @vokilam, не работал у меня.
Работает модифицированная версия @mayqiyue, вызывается во время viewDidLoad
, проводной высоты, равной ширине в виде таблицы.
// Anchor the headerview, and set width equal to superview
NSDictionary *viewsDictionary = @{@"headerView":self.tableView.tableHeaderView,
@"tableView":self.tableView};
[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[headerView]"
options:0
metrics:nil
views:viewsDictionary]];
[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[headerView]"
options:0
metrics:nil
views:viewsDictionary]];
[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[headerView(==tableView)]"
options:0
metrics:nil
views:viewsDictionary]];
[self.tableView.tableHeaderView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[headerView(121)]"
options:0
metrics:nil
views:viewsDictionary]];
Ответ 10
Ниже кодекс работал у меня: -
Добавьте это в свой класс UIView -
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
self.frame = CGRectMake(0, 0, self.frame.size.width, [[self class] height]);
}
return self;
}
Ответ 11
Ответ на @rmigneco работал у меня, поэтому вот его быстрая версия:
let headerFrame = CGRectMake(0, 0, 100, 1);
let tempView = UIView(frame: headerFrame);
tempView.backgroundColor = UIColor.clearColor()
let yourCustomView = CustomView(frame: headerFrame)
tempView.addSubview(yourCustomView)
self.tableView.tableHeaderView = tempView