it-swarm.com.de

Kann Auto Layout mit UITableView tableHeaderView verwendet werden?

Seit ich AutoLayout entdeckt habe, benutze ich es überall. Jetzt versuche ich es mit einem tableHeaderView zu verwenden.

Ich erstellte ein subclass von UIView fügte alles hinzu (Beschriftungen usw.), das ich mit ihren Einschränkungen wollte, und fügte dieses CustomView zum UITableView'tableHeaderView.

Alles funktioniert gut, außer dass UITableView immer über die CustomView anzeigt, mit über ich meine, die CustomView ist unter der UITableView so kann es nicht gesehen werden!

Es scheint, dass, egal was ich tue, die height der UITableView'tableHeaderViewimmer 0 ist (so ist die Breite, x und y).

Meine Frage: Ist es überhaupt möglich, ohne manuelles Einstellen des Rahmens zu erreichen?

EDIT: Die von mir verwendete CustomView'subview hat folgende Einschränkungen:

_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]]]];

Ich verwende eine praktische Bibliothek 'KeepLayout', da das manuelle Schreiben von Einschränkungen für immer und zu viele Zeilen für eine einzige Einschränkung erforderlich ist, aber die Methoden sind selbsterklärend.

Und das UITableView hat folgende Einschränkungen:

_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;

Ich weiß nicht, ob ich einige Einschränkungen direkt auf CustomView setzen muss. Ich denke, die Höhe des CustomView wird durch die Einschränkungen des UILabel "title" bestimmt.

EDIT 2: Nach einer weiteren Untersuchung scheinen die Höhe und Breite des CustomView korrekt berechnet worden zu sein, aber der obere Rand des CustomView befindet sich immer noch auf derselben Ebene wie der obere Teil des UITableView und sie bewegen sich beim Scrollen zusammen.

85
ItsASecret

Ich fragte und beantwortete eine ähnliche Frage hier . Zusammenfassend füge ich den Header einmal hinzu und benutze ihn, um die erforderliche Höhe zu ermitteln. Diese Höhe kann dann auf die Kopfzeile angewendet werden, und die Kopfzeile wird ein zweites Mal festgelegt, um die Änderung widerzuspiegeln.

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

Wenn Sie über mehrzeilige Beschriftungen verfügen, hängt dies auch von der benutzerdefinierten Ansicht ab, in der die Einstellung PreferredMaxLayoutWidth der einzelnen Beschriftungen festgelegt wird:

- (void)layoutSubviews
{
    [super layoutSubviews];

    self.titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.titleLabel.frame);
    self.subtitleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.subtitleLabel.frame);
}

oder vielleicht allgemeiner:

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)
    }
}

Update Januar 2015

Leider scheint dies immer noch notwendig. Hier ist eine schnelle Version des Layoutprozesses:

tableView.tableHeaderView = header
header.setNeedsLayout()
header.layoutIfNeeded()
header.frame.size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
tableView.tableHeaderView = header

Ich fand es nützlich, dies in eine Erweiterung von UITableView zu verschieben:

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

Verwendungszweck:

let header = SCAMessageView()
header.titleLabel.text = "Warning"
header.subtitleLabel.text = "Warning message here."
tableView.setAndLayoutTableHeaderView(header)
120
Ben Packard

Ich konnte keine Kopfansicht mit Einschränkungen (im Code) hinzufügen. Wenn ich meiner Ansicht eine Breite und/oder eine Höhenbeschränkung gebe, stürzt die folgende Meldung ab:

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

Wenn ich meiner Tabellenansicht eine Ansicht im Storyboard hinzufüge, werden keine Einschränkungen angezeigt, und es funktioniert einwandfrei als Kopfansicht. Daher denke ich, dass die Platzierung der Kopfansicht nicht mit Einschränkungen erfolgt. Es scheint sich in dieser Hinsicht nicht wie eine normale Sichtweise zu verhalten.

Die Breite ist automatisch die Breite der Tabellenansicht. Sie müssen lediglich die Höhe einstellen. Die Origin-Werte werden ignoriert. Daher ist es egal, was Sie für diese Werte verwenden. Zum Beispiel hat dies gut funktioniert (ebenso wie 0,0,0,80 für das Rect):

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

Ich habe hier viele Methoden gesehen, die so viel unnötiges Material erledigen, aber Sie brauchen nicht viel Auto-Layout in der Kopfansicht. Sie müssen nur Ihre Xib-Datei erstellen, Ihre Einschränkungen festlegen und diese wie folgt instanziieren: 

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
    }
8

Eine andere Lösung besteht darin, die Erstellung der Header-Ansicht an den nächsten Aufruf des Hauptthreads zu senden:

- (void)viewDidLoad {
    [super viewDidLoad];

    // ....

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

Hinweis: Es behebt den Fehler, wenn die geladene Ansicht eine feste Höhe hat. Ich habe es nicht versucht, wenn die Kopfhöhe nur vom Inhalt abhängt.

EDIT:

Sie können eine sauberere Lösung für dieses Problem finden, indem Sie diese function implementieren und in viewDidLayoutSubviews aufrufen.

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    [self sizeHeaderToFit];
}
6
Martin

Seltsame Dinge passieren. systemLayoutSizeFittingSize eignet sich hervorragend für iOS9, jedoch nicht für iOS 8 in meinem Fall. So löst sich dieses Problem ganz leicht. Rufen Sie den Link in der unteren Ansicht in der Kopfzeile und in viewDidLayoutSubviews nach den Header-Sichteinschränkungen für Super-Aufrufe ab, indem Sie height als CGRectGetMaxY (yourview.frame) + Padding einfügen

UPD: Die einfachste Lösung aller Zeiten : Setzen Sie also in der Kopfansicht die Unteransicht und befestigen Sie sie an left , right , top . Platzieren Sie in dieser Unteransicht Ihre Unteransichten mit Einschränkungen für die automatische Höhe. Danach geben Sie den gesamten Job an das Autolayout weiter (keine Berechnung erforderlich) 

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

Infolgedessen vergrößert/verkleinert sich die Unteransicht, wie sie sollte, und ruft am Ende viewDidLayoutSubviews auf. Zu dem Zeitpunkt, an dem wir die tatsächliche Größe der Ansicht kennen, setzen Sie die HeaderView-Höhe und aktualisieren Sie diese durch erneute Zuweisung. Klappt wunderbar!

Funktioniert auch für die Fußzeile.

3
HotJard

Code:

  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

Mit der Methode " systemLayoutSizeFittingSize " können Sie eine automatische Größenangabe erhalten.

Anschließend können Sie den Rahmen für Ihre Anwendung erstellen. Diese Technik funktioniert immer dann, wenn Sie die Größe einer Ansicht kennen müssen, die Autolayout intern verwendet. 

Der Code in Swift sieht so aus

//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

Oder in 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

Es sollte auch beachtet werden, dass in diesem speziellen Fall das Überschreiben von requiredConstraintBasedLayout in Ihrer Unterklasse dazu führt, dass ein Layout-Durchlauf ausgeführt wird. Die Ergebnisse dieses Layout-Durchlaufs werden jedoch ignoriert und der Systemrahmen auf die Breite der tableView und die Höhe 0 gesetzt.

2
Jonathan

Folgendes hat für mich gearbeitet.

  1. Verwenden Sie eine einfache alte UIView als Kopfansicht.
  2. Hinzufügen von Unteransichten zu dieser UIView
  3. Verwenden Sie Autolayout für die Unteransichten

Der Hauptvorteil, den ich sehe, ist die Begrenzung von Rahmenberechnungen. Apple sollte die API von UITableView wirklich aktualisieren, um dies zu erleichtern.

Beispiel mit 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

Diese Lösung erweitert http://collindonnell.com/2015/09/29/dynamically-sized-table-view-header-or-footer-using-auto-layout/ für die Fußzeile der Tabelle:

@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

Meine Tabellenheaderansicht ist eine UIView-Unterklasse. Ich habe innerhalb des Initialisierers eine einzelne contentView-UIView erstellt, deren Grenzen mit dem Rahmen der Tabellenheaderansicht identisch sind, und alle meine Objekte als Unteransicht davon hinzugefügt.

Fügen Sie dann die Einschränkungen für Ihre Objekte innerhalb der layoutSubviews-Methode der Tabellenkopfansicht und nicht innerhalb des Initialisierers hinzu. Das hat den Absturz gelöst.

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

sie können eine obere und horizontale Standortbedingung zwischen Kopf- und Tabellenansicht hinzufügen, um sie korrekt zu platzieren (wenn der Kopf selbst alle erforderlichen internen Layout-Einschränkungen enthält, um einen korrekten Rahmen zu erhalten).

in der viewDidLoad-Methode tableViewController

    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

Teilen Sie meinen Ansatz.

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

Verwendungszweck. 

[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

Ich konnte es durch den folgenden Ansatz erreichen (dies funktioniert für die Fußzeile genauso).

Zunächst benötigen Sie eine kleine Erweiterung von 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
    }
}

In Ihrer View Controller-Klassenimplementierung:

// 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()
    }
}

Hinweise zu einer Implementierung der Headeransicht UIView:

  1. Sie müssen zu 100% sicher sein, dass Ihre Kopfansicht über das korrekte Setup für das automatische Layout verfügt. Ich würde empfehlen, mit einer einfachen Header-Ansicht mit nur einer Höheneinschränkung zu beginnen und das obige Setup auszuprobieren. 

  2. Überschreiben Sie requiresConstraintBasedLayout und geben Sie true zurück:

.

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

Ich weiß, dass dies ein alter Beitrag ist, aber nachdem ich alle SO -Stellen dazu durchgegangen bin und einen ganzen Nachmittag damit verbracht habe, fand ich schließlich eine saubere und dennoch sehr einfache Lösung 

Meine Ansichtshierarchie sieht zunächst folgendermaßen aus:

  1. Tabellenansicht
    1. tableHeaderView.__ anzeigen.
      1. Ansicht mit einem Ausgang namens headerView 

Jetzt in der Ansicht (Nr. 3) setze ich alle Einschränkungen so ein, wie ich normalerweise den unteren Platz zum Container einschließen würde. Dadurch wird die Größe des Containers (d. H. 3.View, d. H. HeaderView) abhängig von seinen Unteransichten und deren Einschränkungen festgelegt.

Danach setze ich die Einschränkungen zwischen 3. View und 2. View auf diese:

  1. Oben Platz zum Container: 0
  2. Führender Platz zum Container: 0
  3. Leerzeichen bis Container: 0

Beachten Sie, dass ich den unteren Platz absichtlich weglasse.

Sobald dies alles im Storyboard erledigt ist, müssen Sie nur noch diese drei Codezeilen einfügen:

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

So können Sie in Ihrer 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

Ich habe einen Workaround gefunden. Wickeln Sie die Xib-Headeransicht des Autolayout-Wrriten in einen leeren Wrapper für uiview ein, und weisen Sie die Headeransicht der tableViewHeader-Eigenschaft von tableView zu. 

    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

Ein alter Beitrag. Aber ein guter Beitrag. Hier sind meine 2 Cent.

Stellen Sie zunächst sicher, dass die Constraints in der Kopfansicht so angeordnet sind, dass sie ihre eigene intrinsische Inhaltsgröße unterstützen können. Dann machen Sie folgendes.

//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

In meinem Fall hat die Methode mit systemLayoutSizeFittingSize aus irgendeinem Grund nicht funktioniert. Was für mich funktioniert hat, ist eine Modifikation der von HotJard veröffentlichten Lösung (seine ursprüngliche Lösung funktionierte in meinem Fall unter iOS 8 nicht). Ich musste in der Kopfansicht eine Unteransicht platzieren und sie an links, rechts, oben (nicht an unten) befestigen. Fügen Sie alles mit Autolayout in diese Unteransicht ein und führen Sie im Code Folgendes aus:

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

Aktualisiert für 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
        }
    }
}
0
Caleb Friden

Ich bin auf das Problem gestoßen, dass die Breite 375pt ermittelt wurde. Die einzige Möglichkeit, die bei mir funktioniert, besteht darin, die tableView weiterzuleiten, um die richtige Breite zu ermitteln. Ich habe auch AutoLayout der Einstellung der Bildgröße vorgezogen.

Hier ist die Version, die für mich funktioniert:

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 (geändert von der Antwort von @Ben Packard)

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
        self.setNeedsLayout()
        self.layoutIfNeeded()
        header.widthAnchor.widthAnchor.constraint(equalTo: self.bounds.width).isActive = true
        self.tableHeaderView = header
    }
}
0
Baron Ch'ng

Folgendes funktioniert für UITableViewController in iOS 12, 

Legen Sie einen UIView in die TableView über alle Prototypzellen für die Kopfzeile und unter alle Prototypzellen für die Fußzeile. Richten Sie Ihre Kopf- und Fußzeile nach Bedarf ein. Legen Sie alle erforderlichen Bedingungen fest. 

Verwenden Sie nun die folgenden Erweiterungsmethoden

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

und rufen Sie es in ViewDidLayoutSubviews der Unterklasse von UITableViewController auf

public override void ViewDidLayoutSubviews()
{
    base.ViewDidLayoutSubviews();

    TableView.MakeHeaderAutoDimension();
    TableView.MakeFooterAutoDimension();
}
0
HeisenBerg

Für Xamarin-Benutzer:

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

Angenommen, Sie haben die Kopfansicht Ihrer Tableview als TableviewHeader bezeichnet

Mein AutoLayout funktioniert sehr gut:

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;
0
RomanV

Tipps: Wenn Sie die Methode setAndLayoutTableHeaderView verwenden, sollten Sie den Frame der Subviews aktualisieren. In diesem Fall sollte UILabels PreferredMaxLayoutWidth vor dem Aufruf von systemLayoutSizeFittingSize aufgerufen werden. Rufen Sie jedoch nicht in layoutSubview auf.

Code anzeigen

0
user1511613

Jede Constraint-basierte UIView kann eine gute tableHeaderView sein.

Vor tableFooterView und tableFooterView muss eine tableHeaderView gesetzt und dann eine zusätzliche nachstehende Einschränkung auferlegt werden.

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

}

Hier finden Sie alle Details und Codeausschnitte hier

0
malex