it-swarm.com.ru

Можно ли использовать Auto Layout с UITableView tableHeaderView?

Так как я обнаружил AutoLayout, я использую его везде, сейчас я пытаюсь использовать его с tableHeaderView.

Я сделал subclass из UIView добавил все (метки и т.д.), Которые я хотел, с их ограничениями, затем я добавил это CustomView в UITableView'tableHeaderView.

Все работает просто отлично, за исключением того, что UITableView всегда отображает вышеCustomView, выше Я имею в виду, что CustomView --- нижеUITableView, так что это не может быть видел!

Кажется, что независимо от того, что я делаю, heightUITableView'tableHeaderView равно всегда 0 (как и ширина, x и y).

Мой вопрос: возможно ли вообще это сделать без установки фрейма вручную ?

EDIT: Используемое 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" в нем.

EDIT 2: После другого исследования кажется, что высота и ширина CustomView правильно рассчитаны, но верхняя часть CustomView по-прежнему находится на том же уровне, что и верхняя часть UITableView, и они перемещаются вместе, когда я прокрутки.

87
ItsASecret

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

- (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's 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

К сожалению, это все еще кажется необходимым. Вот Swift версия процесса верстки:

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's 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)
125
Ben Packard

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

 "terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super."

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

Ширина автоматически равна ширине табличного представления, единственное, что вам нужно установить, это высота - значения Origin игнорируются, поэтому не имеет значения, что вы вставите для них. Например, это работало нормально (как и 0,0,0,80 для прямой):

UIView *headerview = [[UIView alloc] initWithFrame:CGRectMake(1000,1000, 0, 80)];
headerview.backgroundColor = [UIColor yellowColor];
self.tableView.tableHeaderView = headerview;
24
rdelmar

Я видел здесь много методов, делающих так много ненужных вещей, но вам не нужно так много, чтобы использовать автоматическую разметку в представлении заголовка. Вам просто нужно создать свой 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
    }
12
Ramon Vasconcelos

Другое решение заключается в отправке создания представления заголовка следующему вызову основного потока:

- (void)viewDidLoad {
    [super viewDidLoad];

    // ....

    dispatch_async(dispatch_get_main_queue(), ^{
        _profileView = [[MyView alloc] initWithNib:@"MyView.xib"];
        self.tableView.tableHeaderView = self.profileView;
    });
}

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

РЕДАКТИРОВАТЬ:

Вы можете найти более чистое решение этой проблемы, реализовав это функция и вызвав его в viewDidLayoutSubviews

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    [self sizeHeaderToFit];
}
6
Martin

Странные вещи случаются. systemLayoutSizeFittingSize отлично работает для iOS9, но не для iOS 8 в моем случае. Так что эту проблему решить довольно легко. Просто получите ссылку на нижнее представление в заголовке и в viewDidLayoutSubviews после того, как супер-вызов обновит границы представления заголовка, вставив высоту как CGRectGetMaxY (yourview.frame) + padding

PD: самое простое решение: в заголовке разместите подпредставление и прикрепите его к слева, справа, вверху знак равно В этом подпредставлении разместите ваши подпредставления с ограничениями автоматической высоты. После этого отдайте всю работу на автопрокладку (расчет не требуется)

- (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;
}

В результате подпредставление расширяется/сокращается, как и должно быть, в конце оно вызывает viewDidLayoutSubviews. В то время как мы знаем фактический размер представления, поэтому установите высоту headerView и обновите его, переназначив. Работает как шарм!

Также работает для нижнего колонтитула.

3
HotJard

Код:

  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
          }
  }
3
Phil

Вы можете получить autolayout для предоставления вам размера, используя метод 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

Следует также отметить, что в этом конкретном случае переопределение requireConstraintBasedLayout в вашем подклассе приводит к выполнению этапа макета, однако результаты этого этапа макета игнорируются, а системный кадр устанавливается на ширину tableView и 0 высот.

2
Jonathan

Следующее сработало для меня.

  1. Используйте старый вид UIView в качестве заголовка.
  2. Добавьте подпредставления к этому UIView
  3. Использовать автопоставку в подвиде

Основное преимущество, которое я вижу, - это ограничение рамочных вычислений. 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))
}
2
David Nix

Расширенное решение 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
2
k06a

Мой вид заголовка таблицы - это подкласс UIView - я создал один контент-вид 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
}
1
Ryan

вы можете добавить верхнее + горизонтальное ограничение местоположения между заголовком и табличным представлением, чтобы правильно разместить его (если сам заголовок содержит все необходимые внутренние ограничения макета, чтобы иметь правильный кадр)

в методе 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
1
GreatWiz

Обновлено для 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
        }
    }
}
1
Caleb Friden

Мой 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;
1
RomanV

Поделитесь моим подходом.

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));
    }];
  }];
0
Vincent

Я смог добиться этого с помощью следующего подхода (это работает для нижнего колонтитула так же).

Во-первых, вам понадобится небольшое расширение UITableView:

Swift

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:

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

  2. Переопределите requiresConstraintBasedLayout и верните true:

,.

class MyHeaderView: UIView {
   // ...
   override static var requiresConstraintBasedLayout : Bool {
       return true
   }
   // ...
}
0
Yevhen Dubinin

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

Прежде всего, моя иерархия представлений выглядит так:

  1. Табличное представление
    1. Просмотр tableHeaderView
      1. Просмотр с выходом под названием headerView

Теперь внутри View (№ 3) я установил все ограничения, как обычно, включая нижнее пространство для контейнера. Это приведет к тому, что контейнер (т.е. 3.View, т.е. headerView) изменит свой размер на основе его подпредставлений и их ограничений.

После этого я установил ограничения между 3. View и 2. View следующими:

  1. Верхнее пространство для контейнера: 0
  2. Ведущее пространство для контейнера: 0
  3. Трейлинг-пространство к контейнеру: 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;
}
0
Marc-Alexandre Bérubé

Вот как вы можете сделать это в своем 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)
    }
  }
0
onmyway133

Я нашел обходной путь. оберните ваше представление заголовка xib autolayout wrriten в пустую оболочку 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;
0
tounaobun

Старый пост. Но хороший пост. Вот мои 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)
}
0
user1951992

В моем случае метод с systemLayoutSizeFittingSize почему-то не работал. Что сработало для меня, так это модификация решения, опубликованного HotJard (он также не работал в моем случае на iOS 8). Что мне нужно было сделать, так это в представлении заголовка разместить подпредставление и закрепить его слева, справа, сверху (не прикреплять снизу). Поместите все, используя autolayout в этом подпредставлении и в коде, сделайте это:

- (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;
}
0
Leszek Szary

Вот что работает для 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();
}
0
HeisenBerg

Для пользователей 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

0
Gustavo Baiocchi Costa

Советы: Если вы используете метод setAndLayoutTableHeaderView, вы должны обновить фрейм подпредставлений, поэтому в этой ситуации предпочитаемый метод UILabelMaxLayoutWidth должен вызываться до вызова systemLayoutSizeFittingSize, не вызывать в layoutSubview.

показ кода

0
user1511613

Любое 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;

}

Можно найти все детали и фрагменты кода здесь

0
malex