Можно ли использовать AutoLayout с UITableView tableHeaderView?
Поскольку я обнаружил AutoLayout
, я использую его везде, теперь я пытаюсь использовать его с tableHeaderView
.
Я сделал subclass
of UIView
добавленный все (метки и т.д.). Я хотел с их ограничениями, затем добавил этот CustomView
в UITableView
'tableHeaderView
.
Все работает отлично, за исключением того, что UITableView
всегда показывает выше CustomView
, выше. Я имею в виду CustomView
в < > UITableView
, чтобы его не видно!
Кажется, что независимо от того, что я делаю, height
UITableView
'tableHeaderView
всегда 0 (так же, как ширина, x и y).
Мой вопрос: возможно ли вообще выполнить этот без установки рамки вручную?
РЕДАКТИРОВАТЬ:
CustomView
'subview
, который я использую, имеет следующие ограничения:
_title = [[UILabel alloc]init];
_title.text = @"Title";
[self addSubview:_title];
[_title keep:[KeepTopInset rules:@[[KeepEqual must:5]]]]; // title has to stay at least 5 away from the supperview Top
[_title keep:[KeepRightInset rules:@[[KeepMin must:5]]]];
[_title keep:[KeepLeftInset rules:@[[KeepMin must:5]]]];
[_title keep:[KeepBottomInset rules:@[[KeepMin must:5]]]];
Я использую удобную библиотеку KeepLayout, потому что для записи ограничений вручную требуется навсегда и слишком много строк для одного ограничения, но методы самообучались.
И UITableView
имеет следующие ограничения:
_tableView = [[UITableView alloc]init];
_tableView.translatesAutoresizingMaskIntoConstraints = NO;
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.backgroundColor = [UIColor clearColor];
[self.view addSubview:_tableView];
[_tableView keep:[KeepTopInset rules:@[[KeepEqual must:0]]]];// These 4 constraints make the UITableView stays 0 away from the superview top left right and bottom.
[_tableView keep:[KeepLeftInset rules:@[[KeepEqual must:0]]]];
[_tableView keep:[KeepRightInset rules:@[[KeepEqual must:0]]]];
[_tableView keep:[KeepBottomInset rules:@[[KeepEqual must:0]]]];
_detailsView = [[CustomView alloc]init];
_tableView.tableHeaderView = _detailsView;
Я не знаю, нужно ли мне устанавливать некоторые ограничения непосредственно на CustomView
, я думаю, что высота CustomView определяется ограничениями на UILabel
"title" в нем.
РЕДАКТИРОВАТЬ 2:. После очередного расследования кажется, что высота и ширина CustomView правильно рассчитаны, но верхняя часть CustomView все еще находится на том же уровне, что и верх UITableView, и они перемещаются вместе, когда я прокручиваю.
Ответы
Ответ 1
Я спросил и ответил на аналогичный вопрос здесь. В общем, я добавляю заголовок один раз и использую его, чтобы найти требуемую высоту. Затем эта высота может быть применена к заголовку, а заголовок устанавливается во второй раз, чтобы отразить изменение.
- (void)viewDidLoad
{
[super viewDidLoad];
self.header = [[SCAMessageView alloc] init];
self.header.titleLabel.text = @"Warning";
self.header.subtitleLabel.text = @"This is a message with enough text to span multiple lines. This text is set at runtime and might be short or long.";
//set the tableHeaderView so that the required height can be determined
self.tableView.tableHeaderView = self.header;
[self.header setNeedsLayout];
[self.header layoutIfNeeded];
CGFloat height = [self.header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
//update the header frame and set it again
CGRect headerFrame = self.header.frame;
headerFrame.size.height = height;
self.header.frame = headerFrame;
self.tableView.tableHeaderView = self.header;
}
Если у вас многострочные метки, это также зависит от настройки пользовательского представления предпочтительнойMaxLayoutWidth каждой метки:
- (void)layoutSubviews
{
[super layoutSubviews];
self.titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.titleLabel.frame);
self.subtitleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.subtitleLabel.frame);
}
или, возможно, в целом:
override func layoutSubviews() {
super.layoutSubviews()
for view in subviews {
guard let label = view as? UILabel where label.numberOfLines == 0 else { continue }
label.preferredMaxLayoutWidth = CGRectGetWidth(label.frame)
}
}
Обновление января 2015 г.
К сожалению, это все еще кажется необходимым. Вот быстрая версия процесса компоновки:
tableView.tableHeaderView = header
header.setNeedsLayout()
header.layoutIfNeeded()
header.frame.size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
tableView.tableHeaderView = header
Я нашел полезным переместить это расширение на UITableView:
extension UITableView {
//set the tableHeaderView so that the required height can be determined, update the header frame and set it again
func setAndLayoutTableHeaderView(header: UIView) {
self.tableHeaderView = header
header.setNeedsLayout()
header.layoutIfNeeded()
header.frame.size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
self.tableHeaderView = header
}
}
Использование:
let header = SCAMessageView()
header.titleLabel.text = "Warning"
header.subtitleLabel.text = "Warning message here."
tableView.setAndLayoutTableHeaderView(header)
Ответ 2
Мне не удалось добавить представление заголовка с использованием ограничений (в коде). Если я дам свой вид ширине и/или ограничению высоты, я получаю сообщение об ошибке:
"terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView implementation of -layoutSubviews needs to call super."
Когда я добавляю представление в раскадровку к моему представлению таблицы, он не показывает ограничений, и он отлично работает в виде заголовка, поэтому я считаю, что размещение заголовка не выполняется с использованием ограничений. Похоже, что в этом отношении он не выглядит нормальным.
Ширина автоматически равна ширине представления таблицы, единственное, что вам нужно установить, это высота - значения начала игнорируются, поэтому не имеет значения, что вы вкладываете в них. Например, это работало нормально (как и 0,0,0,80 для прямой):
UIView *headerview = [[UIView alloc] initWithFrame:CGRectMake(1000,1000, 0, 80)];
headerview.backgroundColor = [UIColor yellowColor];
self.tableView.tableHeaderView = headerview;
Ответ 3
Я видел здесь много методов, делающих так много ненужных вещей, но вам не нужно так много использовать автомат в виде заголовка. Вам просто нужно создать файл xib, поместить свои ограничения и создать его таким образом:
func loadHeaderView () {
guard let headerView = Bundle.main.loadNibNamed("CourseSearchHeader", owner: self, options: nil)?[0] as? UIView else {
return
}
headerView.autoresizingMask = .flexibleWidth
headerView.translatesAutoresizingMaskIntoConstraints = true
tableView.tableHeaderView = headerView
}
Ответ 4
Другим решением является отправка создания представления заголовка в следующий вызов основного потока:
- (void)viewDidLoad {
[super viewDidLoad];
// ....
dispatch_async(dispatch_get_main_queue(), ^{
_profileView = [[MyView alloc] initWithNib:@"MyView.xib"];
self.tableView.tableHeaderView = self.profileView;
});
}
Примечание. Исправлена ошибка, когда загруженный вид имел фиксированную высоту. Я не пробовал, когда высота заголовка зависит только от его содержимого.
EDIT:
Вы можете найти более чистое решение этой проблемы, реализовав эту функцию и назовите ее в viewDidLayoutSubviews
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self sizeHeaderToFit];
}
Ответ 5
код:
extension UITableView {
func sizeHeaderToFit(preferredWidth: CGFloat) {
guard let headerView = self.tableHeaderView else {
return
}
headerView.translatesAutoresizingMaskIntoConstraints = false
let layout = NSLayoutConstraint(
item: headerView,
attribute: .Width,
relatedBy: .Equal,
toItem: nil,
attribute:
.NotAnAttribute,
multiplier: 1,
constant: preferredWidth)
headerView.addConstraint(layout)
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
headerView.frame = CGRectMake(0, 0, preferredWidth, height)
headerView.removeConstraint(layout)
headerView.translatesAutoresizingMaskIntoConstraints = true
self.tableHeaderView = headerView
}
}
Ответ 6
Странные вещи случаются. systemLayoutSizeFittingSize отлично работает для iOS9, но не для iOS 8 в моем случае. Поэтому эти проблемы решают довольно легко. Просто получите ссылку на нижний вид в заголовке и в viewDidLayoutSubviews после супервызов заголовка заголовка обновления, вставив высоту в CGRectGetMaxY (yourview.frame) + дополнение
UPD: самое легкое решение когда-либо:
Таким образом, в представлении заголовка разместите subview и привяжите его к левой, справа, верхней. В этом подпункте разместите свои подзоны с ограничениями автоматической высоты. После этого отдайте всю работу автозапуску (не требуется никаких вычислений)
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGFloat height = CGRectGetMaxY(self.tableView.tableHeaderView.subviews.firstObject.frame);
self.tableView.tableHeaderView.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), height);
self.tableView.tableHeaderView = self.tableView.tableHeaderView;
}
В результате subview расширяется/сокращается, как и должно быть, в конце он вызывает viewDidLayoutSubviews. В то время, когда мы знаем фактический размер представления, задаем высоту заголовка и обновляем его путем переназначения.
Работает как шарм!
Также работает для просмотра нижнего колонтитула.
Ответ 7
Вы можете получить автозапуск, чтобы предоставить вам размер с помощью метода systemLayoutSizeFittingSize.
Затем вы можете использовать это для создания фрейма для своего приложения. Эта техника работает всякий раз, когда вам нужно знать размер представления, в котором используется автозапуск внутри.
Код в swift выглядит как
//Create the view
let tableHeaderView = CustomTableHeaderView()
//Set the content
tableHeaderView.textLabel.text = @"Hello world"
//Ask auto layout for the smallest size that fits my constraints
let size = tableHeaderView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
//Create a frame
tableHeaderView.frame = CGRect(origin: CGPoint.zeroPoint, size: size)
//Set the view as the header
self.tableView.tableHeaderView = self.tableHeaderView
Или в Objective-C
//Create the view
CustomTableHeaderView *header = [[CustomTableHeaderView alloc] initWithFrame:CGRectZero];
//Set the content
header.textLabel.text = @"Hello world";
//Ask auto layout for the smallest size that fits my constraints
CGSize size = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
//Create a frame
header.frame = CGRectMake(0,0,size.width,size.height);
//Set the view as the header
self.tableView.tableHeaderView = header
Следует также отметить, что в этом конкретном случае переопределение требуетConstraintBasedLayout в вашем подклассе, приводит к выполнению прохода макета, однако результаты этого макета пропуска игнорируются, а системный фрейм устанавливается на ширину таблицыView и 0 высота.
Ответ 8
Следующие работали для меня.
- Используйте обычный старый
UIView
как вид заголовка.
- Добавить подзаголовки к этому
UIView
- Использовать автозапуск в подзаголовках
Основное преимущество, которое я вижу, - это ограничение вычислений кадров. Apple должна действительно обновить API UITableView
, чтобы сделать это проще.
Пример использования SnapKit:
let layoutView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 60))
layoutView.backgroundColor = tableView.backgroundColor
tableView.tableHeaderView = layoutView
let label = UILabel()
layoutView.addSubview(label)
label.text = "I'm the view you really care about"
label.snp_makeConstraints { make in
make.edges.equalTo(EdgeInsets(top: 10, left: 15, bottom: -5, right: -15))
}
Ответ 9
Расширенное это решение http://collindonnell.com/2015/09/29/dynamically-sized-table-view-header-or-footer-using-auto-layout/ для просмотра нижнего колонтитула стола:
@interface AutolayoutTableView : UITableView
@end
@implementation AutolayoutTableView
- (void)layoutSubviews {
[super layoutSubviews];
// Dynamic sizing for the header view
if (self.tableHeaderView) {
CGFloat height = [self.tableHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
CGRect headerFrame = self.tableHeaderView.frame;
// If we don't have this check, viewDidLayoutSubviews() will get
// repeatedly, causing the app to hang.
if (height != headerFrame.size.height) {
headerFrame.size.height = height;
self.tableHeaderView.frame = headerFrame;
self.tableHeaderView = self.tableHeaderView;
}
[self.tableHeaderView layoutIfNeeded];
}
// Dynamic sizing for the footer view
if (self.tableFooterView) {
CGFloat height = [self.tableFooterView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
CGRect footerFrame = self.tableFooterView.frame;
// If we don't have this check, viewDidLayoutSubviews() will get
// repeatedly, causing the app to hang.
if (height != footerFrame.size.height) {
footerFrame.size.height = height;
self.tableFooterView.frame = footerFrame;
self.tableFooterView = self.tableFooterView;
}
self.tableFooterView.transform = CGAffineTransformMakeTranslation(0, self.contentSize.height - footerFrame.size.height);
[self.tableFooterView layoutIfNeeded];
}
}
@end
Ответ 10
Обновлено для Swift 4.2
extension UITableView {
var autolayoutTableViewHeader: UIView? {
set {
self.tableHeaderView = newValue
guard let header = newValue else { return }
header.setNeedsLayout()
header.layoutIfNeeded()
header.frame.size =
header.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
self.tableHeaderView = header
}
get {
return self.tableHeaderView
}
}
}
Ответ 11
Мой заголовок таблицы является подклассом UIView - я создал единый contentView UIView в инициализаторе, с его границами, такими же, как и заголовок таблицы заголовка таблицы, и добавил все мои объекты в качестве подзадачи этого.
Затем добавьте ограничения для ваших объектов в виде представления заголовка таблицы layoutSubviews
, а не в инициализаторе. Это решило крах.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:CGRectMake(0, 0, 0, 44.0)];
if (self) {
UIView *contentView = [[UIView alloc] initWithFrame:self.bounds];
contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
// add other objects as subviews of content view
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// remake constraints here
}
Ответ 12
вы можете добавить ограничение верхнего и горизонтального местоположения между заголовком и таблицей, чтобы правильно разместить его (если сам заголовок содержит все необходимые внутренние ограничения макета, чтобы иметь правильный фрейм)
в методе tableViewController viewDidLoad
headerView.translatesAutoresizingMaskIntoConstraints = false
tableView.tableHeaderView = headerView
headerView.widthAnchor.constraint(equalTo: tableView.widthAnchor).isActive = true
headerView.topAnchor.constraint(equalTo: tableView.topAnchor).isActive = true
headerView.centerXAnchor.constraint(equalTo: tableView.centerXAnchor).isActive = true
Ответ 13
Мой AutoLayout работает очень хорошо:
CGSize headerSize = [headerView systemLayoutSizeFittingSize:CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds), 0) withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
headerView.frame = CGRectMake(0, 0, headerSize.width, headerSize.height);
self.tableView.tableHeaderView = headerView;
Ответ 14
Я знаю, что это старый пост, но, пройдя все сообщения SO по этому поводу и пропустив целый день, играя с этим, я наконец придумал чистое, но очень простое решение.
Прежде всего, иерархия My view выглядит следующим образом:
- Просмотр таблицы
- Просмотр
tableHeaderView
- Просмотр с выходом под названием headerView
Теперь внутри представления (№ 3) я установил все ограничения, как обычно, включая нижнее пространство для контейнера. Это сделает контейнер (т.е. 3.View, т.е. HeaderView), чтобы сам по себе основывался на его подзонах и их ограничениях.
После этого я устанавливаю ограничения между 3. View
и 2. View
следующими:
- Верхнее пространство в контейнере: 0
- Ведущее пространство в контейнере: 0
- Конечное пространство в контейнере: 0
Обратите внимание, что я намеренно упускаю сознательно нижнее пространство.
Как только все это будет сделано в раскадровке, все, что осталось сделать, это вставить эти три строки кодов:
if (self.headerView.frame.size.height != self.tableView.tableHeaderView.frame.size.height) {
UIView *header = self.tableView.tableHeaderView;
CGRect frame = self.tableView.tableHeaderView.frame;
frame.size.height = self.headerView.frame.size.height + frame.origin.y;
header.frame = frame;
self.tableView.tableHeaderView = header;
}
Ответ 15
Советы. Если вы используете метод setAndLayoutTableHeaderView, вам следует обновить фрейм подкадров, поэтому в этой ситуации UILabel, предпочтительныйMaxLayoutWidth должен вызывать до вызова systemLayoutSizeFittingSize, не вызывать в layoutSubview.
показать код
Ответ 16
Поделитесь моим подходом.
UITableView+XXXAdditions.m
- (void)xxx_setTableHeaderView:(UIView *)tableHeaderView layoutBlock:(void(^)(__kindof UIView *tableHeaderView, CGFloat *containerViewHeight))layoutBlock {
CGFloat containerViewHeight = 0;
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
[backgroundView addSubview:tableHeaderView];
layoutBlock(tableHeaderView, &containerViewHeight);
backgroundView.frame = CGRectMake(0, 0, 0, containerViewHeight);
self.tableHeaderView = backgroundView;
}
Использование.
[self.tableView xxx_setTableHeaderView:myView layoutBlock:^(__kindof UIView * _Nonnull tableHeaderView, CGFloat *containerViewHeight) {
*containerViewHeight = 170;
[tableHeaderView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(@20);
make.centerX.equalTo(@0);
make.size.mas_equalTo(CGSizeMake(130, 130));
}];
}];
Ответ 17
В моем случае метод с systemLayoutSizeFittingSize по какой-то причине не работал. Что сработало для меня, это модификация решения, опубликованного HotJard (его оригинальное решение также не работало в моем случае на iOS 8). То, что мне нужно было сделать, - это заголовок в представлении subview и привязать его к левому, правому, верхнему (не привязывать к нижней части). Поместите все, используя автозапуск в этом подвью и в коде выполните следующее:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self resizeHeaderToFitSubview];
}
- (void)resizeHeaderToFitSubview
{
UIView *header = self.tableView.tableHeaderView;
[header setNeedsLayout];
[header layoutIfNeeded];
CGFloat height = CGRectGetHeight(header.subviews.firstObject.bounds);
header.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), height);
self.tableView.tableHeaderView = nil;
self.tableView.tableHeaderView = header;
}
Ответ 18
Старый пост. Но хороший пост. Вот мои 2 цента.
Во-первых, убедитесь, что в вашем представлении заголовка установлены ограничения, чтобы он мог поддерживать собственный собственный размер содержимого. Затем выполните следующие действия.
//ViewDidLoad
headerView.translatesAutoresizingMaskIntoConstraints = false
headerView.configure(title: "Some Text A")
//Somewhere else
headerView.update(title: "Some Text B)
private var widthConstrained = false
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if widthConstrained == false {
widthConstrained = true
tableView.addConstraint(NSLayoutConstraint(item: headerView, attribute: .width, relatedBy: .equal, toItem: tableView, attribute: .width, multiplier: 1, constant: 0))
headerView.layoutIfNeeded()
tableView.layoutIfNeeded()
}
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { (context) in
self.headerView.layoutIfNeeded()
self.tableView.layoutIfNeeded()
}, completion: nil)
}
Ответ 19
Мне удалось достичь этого с помощью следующего подхода (это работает для нижнего колонтитула одинаково).
Сначала вам понадобится небольшое расширение UITableView
:
Swift 3
extension UITableView {
fileprivate func adjustHeaderHeight() {
if let header = self.tableHeaderView {
adjustFrame(header)
}
}
private func adjustFrame(_ view: UIView) {
view.frame.size.height = calculatedViewHeight(view)
}
fileprivate func calculatedHeightForHeader() -> CGFloat {
if let header = self.tableHeaderView {
return calculatedViewHeight(header)
}
return 0.0
}
private func calculatedViewHeight(_ view: UIView) -> CGFloat {
view.setNeedsLayout()
let height = view.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
return height
}
}
В вашем представлении класса контроллера:
// this is a UIView subclass with autolayout
private var headerView = MyHeaderView()
override func loadView() {
super.loadView()
// ...
self.tableView.tableHeaderView = headerView
self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension
// ...
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
// this is to prevent recursive layout calls
let requiredHeaderHeight = self.tableView.calculatedHeightForHeader()
if self.headerView.frame.height != requiredHeaderHeight {
self.tableView.adjustHeaderHeight()
}
}
Примечания о заголовке UIView
реализация subview:
-
У вас должно быть 100% уверенность, что в вашем представлении заголовка установлена правильная настройка автоопределения. Я бы рекомендовал начать с простого заголовка с одним ограничением по высоте и опробовать настройку выше.
-
Заменить requiresConstraintBasedLayout
и вернуть true
:
.
class MyHeaderView: UIView {
// ...
override static var requiresConstraintBasedLayout : Bool {
return true
}
// ...
}
Ответ 20
Для пользователей Xamarin:
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
TableviewHeader.SetNeedsLayout();
TableviewHeader.LayoutIfNeeded();
var height = TableviewHeader.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize).Height;
var frame = TableviewHeader.Frame;
frame.Height = height;
TableviewHeader.Frame = frame;
}
Предполагая, что вы назвали представление заголовка своего табличного представления как TableviewHeader
Ответ 21
Вот как вы можете сделать это в своем UIViewController
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if headerView.frame.size.height == 0 {
headerView.label.preferredMaxLayoutWidth = view.bounds.size.width - 20
let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
headerView.frame.size = CGSize(width: tableView.bounds.size.width, height: height)
}
}
Ответ 22
Любой основанный на ограничениях UIView
может быть хорошим tableHeaderView
.
Необходимо предварительно установить tableFooterView
а затем наложить дополнительные конечные ограничения на tableFooterView
и tableHeaderView
.
- (void)viewDidLoad {
........................
// let self.headerView is some constraint-based UIView
self.tableView.tableFooterView = [UIView new];
[self.headerView layoutIfNeeded];
self.tableView.tableHeaderView = self.headerView;
[self.tableView.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor].active = YES;
[self.tableView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor].active = YES;
[self.tableView.topAnchor constraintEqualToAnchor:self.headerView.topAnchor].active = YES;
[self.tableFooterView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor].active = YES;
}
Все подробности и фрагменты кода можно найти здесь
Ответ 23
Я придумал обходное решение. оберните свой заголовок заголовком xml-заголовка для авторизации в пустой оболочке uiview и назначьте представление заголовка для свойства tableView tableViewHeader.
UIView *headerWrapper = [[UIView alloc] init];
AXLHomeDriverHeaderView *headerView = [AXLHomeDriverHeaderView loadViewFromNib];
[headerWrapper addSubview:headerView];
[headerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(headerWrapper);
}];
self.tableView.tableHeaderView = headerView;
Ответ 24
Вот что работает для UITableViewController в ios 12,
Нарисуйте UIView в TableView над всеми ячейками прототипа для заголовка и под всеми ячейками прототипа для нижнего колонтитула. Настройте верхний и нижний колонтитулы по мере необходимости. Установите все необходимые ограничения.
Теперь используйте следующие методы расширения
public static class UITableVIewExtensions
{
public static void MakeHeaderAutoDimension(this UITableView tableView)
{
if (tableView.TableHeaderView is UIView headerView) {
var size = headerView.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize);
if (headerView.Frame.Size.Height != size.Height) {
var frame = headerView.Frame;
frame.Height = size.Height;
headerView.Frame = frame;
tableView.TableHeaderView = headerView;
tableView.LayoutIfNeeded();
}
}
}
public static void MakeFooterAutoDimension(this UITableView tableView)
{
if (tableView.TableFooterView is UIView footerView) {
var size = footerView.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize);
if (footerView.Frame.Size.Height != size.Height) {
var frame = footerView.Frame;
frame.Height = size.Height;
footerView.Frame = frame;
tableView.TableFooterView = footerView;
tableView.LayoutIfNeeded();
}
}
}
}
и вызвать его в ViewDidLayoutSubviews подкласса UITableViewController
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
TableView.MakeHeaderAutoDimension();
TableView.MakeFooterAutoDimension();
}
Ответ 25
Я столкнулся с проблемой получения ширины 375pt, единственный способ, который работал для меня, - это ретранслировать tableView, чтобы получить правильную ширину. Я также предпочел AutoLayout над настройкой размера кадра.
Вот версия, которая работает для меня:
Xamarin.iOS
public static void AutoLayoutTableHeaderView(this UITableView tableView, UIView header)
{
tableView.TableHeaderView = header;
tableView.SetNeedsLayout();
tableView.LayoutIfNeeded();
header.WidthAnchor.ConstraintEqualTo(tableView.Bounds.Width).Active = true;
tableView.TableHeaderView = header;
}
Swift Version (модифицировано из ответа @Ben Packard)
extension UITableView {
//set the tableHeaderView so that the required height can be determined, update the header frame and set it again
func setAndLayoutTableHeaderView(header: UIView) {
self.tableHeaderView = header
self.setNeedsLayout()
self.layoutIfNeeded()
header.widthAnchor.widthAnchor.constraint(equalTo: self.bounds.width).isActive = true
self.tableHeaderView = header
}
}
Ответ 26
Принятый ответ полезен только для таблиц с одним разделом. Для multi-section UITableView
просто убедитесь, что ваш заголовок наследует от UITableViewHeaderFooterView
, и все будет в порядке.
В качестве альтернативы просто вставьте свой текущий заголовок в contentView
UITableViewHeaderFooterView
. Точно как UITableViewCell
работает.