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
'tableHeaderView
immer 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.
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)
}
}
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)
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;
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
}
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];
}
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.
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
}
}
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.
Folgendes hat für mich gearbeitet.
UIView
als Kopfansicht.UIView
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))
}
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
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
}
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
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));
}];
}];
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
:
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.
Überschreiben Sie requiresConstraintBasedLayout
und geben Sie true
zurück:
.
class MyHeaderView: UIView {
// ...
override static var requiresConstraintBasedLayout : Bool {
return true
}
// ...
}
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:
tableHeaderView
.__ anzeigen.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:
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)
}
}
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;
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)
}
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;
}
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
}
}
}
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:
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;
}
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
}
}
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();
}
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;
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.
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