自从我发现AutoLayout
以来,我在任何地方都使用它,现在我正尝试将它与tableHeaderView
一起使用。
我制作了UIView
的subclass
,添加了我想要的所有内容(标签等(及其约束,然后我将这个CustomView
添加到UITableView
’tableHeaderView
中。
一切都很好,除了UITableView
总是在CustomView
的上方显示,我的意思是CustomView
在UITableView
的下方,所以看不见!
似乎无论我做什么,UITableView
'tableHeaderView
的height
总是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
"标题"的约束决定的。
编辑2:经过另一次调查,CustomView的高度和宽度似乎计算正确,但CustomView的顶部仍然与UITableView的顶部处于同一水平,当我滚动时,它们会一起移动。
我在这里问并回答了一个类似的问题。总之,我添加了一次标题,并使用它来查找所需的高度。然后可以将该高度应用于收割台,并第二次设置收割台以反映更改。
- (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;
}
如果您有多行标签,这也依赖于自定义视图设置每个标签的preferredMaxLayoutWidth:
- (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年1月更新
不幸的是,这似乎仍然是必要的。以下是布局过程的快速版本:
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
self.tableHeaderView?.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
header.widthAnchor.constraint(equalTo: self.widthAnchor)
])
header.setNeedsLayout()
header.layoutIfNeeded()
header.frame.size = header.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
self.tableHeaderView = header
}
}
用法:
let header = SCAMessageView()
header.titleLabel.text = "Warning"
header.subtitleLabel.text = "Warning message here."
tableView.setAndLayoutTableHeaderView(header)
我无法使用约束(在代码中(添加头视图。如果我给我的视图一个宽度和/或高度限制,我会崩溃,消息是:
"terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super."
当我将情节提要中的视图添加到表视图中时,它不显示任何约束,而且它可以很好地用作标题视图,所以我认为标题视图的放置不是使用约束完成的。在这方面,它似乎不像一个正常的观点。
宽度自动是表视图的宽度,您只需要设置高度——原点值被忽略,所以您为这些值输入什么并不重要。例如,这很好(rect的0,0,0,80也是如此(:
UIView *headerview = [[UIView alloc] initWithFrame:CGRectMake(1000,1000, 0, 80)];
headerview.backgroundColor = [UIColor yellowColor];
self.tableView.tableHeaderView = headerview;
我看到这里有很多方法做了很多不必要的事情,但在头视图中使用自动布局并不需要那么多。您只需要创建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
}
另一个解决方案是将头视图创建调度到下一个主线程调用:
- (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];
}
您可以使用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
还应该注意的是,在这个特定的实例中,在子类中重写requiresConstraintBasedLayout确实会导致执行布局过程,但是该布局过程的结果会被忽略,并且系统框架设置为tableView的宽度和0的高度。
代码:
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
}
}
扩展了此解决方案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
针对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
}
}
}
以下内容对我有效。
- 使用普通的旧
UIView
作为标头视图 - 将子视图添加到
UIView
- 在子视图上使用自动布局
我看到的主要好处是限制帧计算。苹果真的应该更新UITableView
的API,让它更容易。
使用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))
}
奇怪的事情发生了。systemLayoutSizeFittingSize适用于iOS9,但在我的情况下不适用于iOS8。所以这个问题很容易解决。只需在超级调用后通过插入高度为CGRectGetMaxY(yourview.frame(+填充来更新标头视图边界,即可在标头和viewDidLayoutSubviews中获得底部视图的链接
UPD:有史以来最简单的解决方案:因此,在页眉视图中放置子视图,并将其固定到左侧、右侧和顶部。在该子视图中放置具有自动高度约束的子视图。之后,将所有作业交给自动布局(无需计算(
- (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高度并通过重新分配进行更新。工作起来很有魅力!
也适用于页脚视图。
您可以在页眉和表视图之间添加顶部+水平位置约束,以正确放置它(如果页眉本身包含所有必要的内部布局约束,以获得正确的框架(
在表中ViewController视图DidLoad方法
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
在大多数情况下,最好的解决方案就是不对抗框架,而采用自动resizing掩码:
// embrace autoresizing masks and let the framework add the constraints for you
headerView.translatesAutoresizingMaskIntoConstraints = true
headerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// figure out what's the best size based on the table view width
let width = self.tableView.frame.width
let targetSize = headerView.systemLayoutSizeFitting(CGSize(width: width, height: CGFloat.greatestFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
headerView.frame.size = targetSize
self.tableView.tableHeaderView = headerView
通过使用自动resizing掩码,您可以告诉框架当超级视图更改其大小时,您的视图应该如何更改其大小。但此更改是基于您设置的初始帧。
我的解决方案正在创建一个这样的新类。
class BaseTableHeaderView: UIView {
func sizeToFitBasedOnConstraints(width: CGFloat = Screen.width) {
let size = systemLayoutSizeFitting(CGSize(width: width, height: 10000),
withHorizontalFittingPriority: .required,
verticalFittingPriority: .fittingSizeLevel)
frame = CGRect(origin: .zero, size: size)
}
override func willMove(toSuperview newSuperview: UIView?) {
sizeToFitBasedOnConstraints()
super.willMove(toSuperview: newSuperview)
}
}
要使用它,只需将所有子视图添加到BaseTableHeaderView
的实例中,并将其附加到表视图中。
let tableHeaderView = BaseTableHeaderView()
tableHeaderView.addSubview(...)
tableView.tableHeaderView = tableHeaderView
它将根据其约束自动调整大小。
我的表头视图是一个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
}
我的自动布局运行得很好:
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;
我知道这是一个老帖子,但在浏览了所有关于这一点的SO帖子并花了一个下午的时间玩了这个之后,我终于想出了一个干净但非常简单的解决方案
首先,我的视图层次结构如下:
- 表格视图
- 查看
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;
}
提示:如果使用方法setAndLayoutTableHeaderView,则应更新子视图的框架,因此在这种情况下,UILabel的preferredMaxLayoutWidth应在调用systemLayoutSizeFittingSize之前调用,不要在layoutSubview中调用。
代码显示
分享我的方法。
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));
}];
}];
一篇旧帖子。但这是一个不错的帖子。这是我的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)
}
我能够通过以下方法实现它(这对页脚也是一样的(。
首先,您将需要小型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
的子视图实现的注意事项:
您必须100%确保您的页眉视图具有正确的自动布局设置。我建议从只有一个高度约束的简单标头视图开始,并尝试上面的设置。
覆盖
requiresConstraintBasedLayout
并返回true
:
class MyHeaderView: UIView {
// ...
override static var requiresConstraintBasedLayout : Bool {
return true
}
// ...
}
对于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
以下是如何在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)
}
}
任何基于约束的UIView
都可以是一个好的tableHeaderView
。
需要在CCD_ 38和CCD_ 39之前设置CCD_。
- (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;
}
可以在这里找到所有细节和代码片段
我已经找到了一个解决方法。将您的自动布局wrriten-xib头视图包装在一个空的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;
以下是适用于ios 12、中UITableViewController的功能
在页眉的所有原型单元格上方和页脚的所有原型单元下方的TableView中绘制UIView。根据需要设置页眉和页脚。设置所有必需的约束。
现在使用以下扩展方法
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();
}
}
}
}
并在UITableViewController 子类的ViewDidLayoutSubviews中调用它
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
TableView.MakeHeaderAutoDimension();
TableView.MakeFooterAutoDimension();
}
我遇到了获取375pt宽度的问题,对我来说唯一有效的方法是重新发布tableView以获取正确的宽度。我也更喜欢"自动布局"而不是设置"框架大小"。
这是适用于我的版本:
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版本(根据@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
}
}
我创建了UITableView
的子类,并将UIStackView
用于页眉和页脚,它还允许设置多个视图。
https://github.com/omaralbeik/StackableTableView
在检查了其他曾经有效但不再有效的解决方案后,我为具有多行标签的头视图创建了以下解决方案,该解决方案在iOS 12、iOS13,IOS14和iOS 15上运行良好,在任何情况下都可以使用设备旋转。不要直接将视图设置为表头视图,而是使用一个包装视图,如果实际视图更改了高度,该视图会自动更新其高度。将以下类添加到您的项目中:
class TableViewHeaderHelperView: UIView {
private weak var headerView: UIView?
private weak var tableView: UITableView?
private var lastUpdatedHeight: CGFloat = 0
init(headerView: UIView) {
self.headerView = headerView
super.init(frame: .zero)
translatesAutoresizingMaskIntoConstraints = true
addSubview(headerView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addToTableView(_ tableView: UITableView) {
self.tableView = tableView
tableView.tableHeaderView = self
headerView?.widthAnchor.constraint(equalTo: tableView.widthAnchor).isActive = true
}
func removeFromTableView() {
self.tableView?.tableHeaderView = nil
self.tableView = nil
}
override func layoutSubviews() {
super.layoutSubviews()
refreshHeaderHeightIfNeeded()
}
func refreshHeaderHeightIfNeeded() {
DispatchQueue.main.async {
let headerViewSize = self.headerView?.bounds.size ?? .zero
if headerViewSize.height != self.lastUpdatedHeight {
self.lastUpdatedHeight = headerViewSize.height
self.frame.size = headerViewSize
self.tableView?.tableHeaderView = self
}
}
}
}
然后你可以使用这个助手类如下:
let headerWrapperView = TableViewHeaderHelperView(headerView: yourRealHeaderView)
headerWrapperView.addToTableView(tableView)
或者,我在我的库LSCategories中也使用了类似的方法,该方法提供了各种扩展,包括UITableView类的扩展,该类允许用一行代码在页眉视图或页脚视图中设置自动布局视图,因此您也可以尝试。
接受的答案仅对具有单个部分的表有用。对于多节UITableView
,只需确保您的标头继承自UITableViewHeaderFooterView
即可。
作为替代方案,只需将当前标头嵌入到UITableViewHeaderFooterView
的contentView
中即可。就像UITableViewCell
一样。