35

I am trying to create a header view for my uiTableView (not a section header, I already have those.) I have set up an XIB in interface builder. All the connections are hooked up and it runs beautifully... except the table doesn't give it enough room! My problem is that the top of the table overlaps the table's header by a little.

My XIB is setup with autlayout for all the buttons, and IB is happy that the constraints don't conflict / ambiguous. The view is set to Freeform size, which in my case ended up being 320 x 471. Then in constraints for the view, I set an intrinsic size for the view of the same.

Now this works perfectly with my table. Everything looks great. But if I manually change any of the fonts in the header view with code, the layout makes the view bigger, and it ends up underneath my table.

Any ideas how to get the tableviewcontroller to leave enough room for the header view after setting fonts and sizes? I hope I've made sense explaining this.

4

11 回答 11

65

注意:可以在此处找到 Swift 3+ 版本:https ://gist.github.com/marcoarment/1105553afba6b4900c10#gistcomment-1933639


这个想法是在systemLayoutSizeFittingSize:targetSize.

返回满足其约束的视图的大小。考虑到它拥有的所有约束及其子视图的约束,确定视图的最佳大小。

更改标题的高度后,需要重新分配tableHeaderView属性以调整表格单元格。

基于这个答案:Using Auto Layout in UITableView for dynamic cell layouts & variable row heights

- (void)sizeHeaderToFit
{
    UIView *header = self.tableView.tableHeaderView;

    [header setNeedsLayout];
    [header layoutIfNeeded];

    CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
    CGRect frame = header.frame;

    frame.size.height = height;
    header.frame = frame;

    self.tableView.tableHeaderView = header;
}
于 2014-01-13T19:13:29.647 回答
15

当我尝试将表视图标题设置为使用界面生成器使用自动布局定义的自定义视图时,我遇到了类似的问题。

当我这样做时,我会发现它会被部分标题所掩盖。

我的工作涉及使用“虚拟视图”作为表头视图,然后将我的自定义视图作为子视图添加到该虚拟视图。我认为这允许自动布局根据约束和包含视图的框架来配置外观。这可能不像 vokilam 的解决方案那么优雅,但它对我有用。


CGRect headerFrame = CGRectMake(0, 0, yourWidth, yourHeight);
UIView *tempView = [[UIView alloc] initWithFrame:headerFrame];
[tempView setBackgroundColor:[UIColor clearColor]];
YourCustomView *customView = [[YourCustomView alloc] initWithFrame: headerFrame];
[tempView addSubview:movieHeader];
self.tableView.tableHeaderView = tempView;
于 2014-06-10T19:00:06.077 回答
9

因为您是具有自动布局tableHeaderView的初始表单,所以您的自定义约束是未知的。您应该添加自定义的:xibheaderViewsuperViewconstraintsheaderView

1.inviewDidLLoad将您的自定义 headerView 分配给 tableView 的 tableHeaderView

 - (void)viewDidLoad
{
    [super viewDidLoad];
    UIView *yourHeaderView = [[[NSBundle mainBundle] loadNibNamed:@"yourHeaderView" owner:nil options:nil] objectAtIndex:0];
    //important:turn off the translatesAutoresizingMaskIntoConstraints;apple documents for details
     yourHeaderView.translatesAutoresizingMaskIntoConstraints = NO;
    self.tableView.tableHeaderView = yourHeaderView;
}

2.in - (void)updateViewConstraints,添加自定义headerView的基本约束

- (void)updateViewConstraints
{
    NSDictionary *viewsDictionary = @{@"headerView":yourHeaderView};

    NSArray *constraint_V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[headerView(121)]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];

    NSArray *constraint_H = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[headerView(320)]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];
    [self.headerView addConstraints:constraint_H];
    [self.headerView addConstraints:constraint_V];

    NSArray *constraint_POS_V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[headerView]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];

    NSArray *constraint_POS_H = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[headerView]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];
    [self.tableView addConstraints:constraint_POS_V];
    [self.tableView addConstraints:constraint_POS_H];

    [super updateViewConstraints];
}

好的!PS:这里是相关文档:Resizing the View Controller's Views

于 2015-01-11T07:33:17.400 回答
8

解决我的问题的是:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    sizeHeaderToFit()
}

private func sizeHeaderToFit() { 
    if let headerView = tableView.tableHeaderView {

        headerView.setNeedsLayout()
        headerView.layoutIfNeeded()

        let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
        var newFrame = headerView.frame

        // Needed or we will stay in viewDidLayoutSubviews() forever
        if height != newFrame.size.height {
            newFrame.size.height = height
            headerView.frame = newFrame

            tableView.tableHeaderView = headerView
        }
    }
}

我在某个地方找到了这个解决方案,并且工作起来很有魅力,但我不记得在哪里了。

于 2016-08-24T12:22:23.290 回答
4

我发现 vokilam 的答案很好用。这是他在 Swift 中的解决方案。

func sizeHeaderToFit() {
    guard let header = tableView.tableHeaderView else { return }
    header.setNeedsLayout()
    header.layoutIfNeeded()
    let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    header.frame.size.height = height
    tableView.tableHeaderView = header
}
于 2016-01-07T18:35:21.170 回答
1

在我的情况下systemLayoutSizeFittingSize,返回不正确的大小,因为其中一个子视图使用纵横比(宽高)4:1 约束。

在我将其更改为恒定高度约束值 (100) 后,它开始按预期工作。

于 2016-09-08T15:08:19.863 回答
1

其他答案为我指明了正确调整 tableHeaderView 大小的方向。但是,我在标题和 tableView 单元格之间出现了差距。这也可能导致您的单元格与标题重叠,具体取决于标题是变大还是变小。

我从这个出发:

 tableView.reloadData()
 let height = tableViewHeader.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
 tableView.tableHeaderView?.frame.size.height = height

要修复间隙/重叠,我所要做的就是将 tableView.reloadData() 移动到设置新高度之后而不是之前。

对此:

 let height = tableViewHeader.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
 tableView.tableHeaderView?.frame.size.height = height
 tableView.reloadData()
于 2017-04-25T19:01:05.930 回答
1

结合@SwiftArchitect、@vokilam 和@mayqiyue 的答案,并使用以编程方式创建tableHeaderView的而不是笔尖(尽管我看不出它不应该与笔尖一起使用的任何理由),并且在iOS 10.x/ Xcode 8.2.1,这是我的工作:

在您的视图控制器的-viewDidLoad或 -init方法中创建视图,或者在您使用表视图的任何地方创建视图:

MyCustomTableHeaderView *myCustomTableHeaderView = [[MyCustomTableHeaderView alloc] init]; // Don't set its frame
myCustomTableHeaderView.translatesAutoresizingMaskIntoConstraints = NO;
self.myTableView.tableHeaderView = myCustomTableHeaderView;
self.myCustomTableHeaderView = myCustomTableHeaderView;  // We set and update our constraints in separate methods so we store the table header view in a UIView property to access it later

无论您在哪里设置自定义标题视图的约束(可以在 `updateConstraints 但此方法可以多次调用):

// We use Pure Layout in our project, but the workflow is the same:
// Set width and height constraints on your custom view then pin it to the top and left of the table view
// Could also use VFL or NSLayoutConstraint methods
[self.myCustomTableHeaderView autoSetDimension:ALDimensionWidth toSize:CGRectGetWidth(self.superview.frame)]; // Width set to tableview's width
[self.myCustomTableHeaderView autoSetDimension:ALDimensionHeight toSize:height]; // Whatever you want your height to be
[self.myCustomTableHeaderView autoPinEdgeToSuperviewEdge:ALEdgeTop];
[self.myCustomTableHeaderView autoPinEdgeToSuperviewEdge:ALEdgeLeft];

// This is important
[self.myCustomTableHeaderView layoutIfNeeded]; // We didn't need to call -setNeedsLayout or reassign our custom header view to the table view's tableHeaderView property again, as was noted in other answers
于 2017-03-31T15:49:06.110 回答
0

下面的代码对我有用:-在您的 UIView 类中添加它-

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];

if (self) {
    self.frame = CGRectMake(0, 0, self.frame.size.width, [[self class] height]);
}

return self;

}

于 2015-10-12T07:08:08.723 回答
0

sizeHeaderToFit@vokilam 建议的对我不起作用。

起作用的是@mayqiyue 的修改版本,在 期间调用viewDidLoad,有线高度,与表格视图相等的宽度。

// Anchor the headerview, and set width equal to superview
NSDictionary *viewsDictionary = @{@"headerView":self.tableView.tableHeaderView,
                                  @"tableView":self.tableView};

[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[headerView]"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[headerView]"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[headerView(==tableView)]"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
[self.tableView.tableHeaderView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[headerView(121)]"
                                                                                       options:0
                                                                                       metrics:nil
                                                                                         views:viewsDictionary]];
于 2015-07-23T05:52:06.287 回答
0

@rmigneco 回答对我有用,所以这是它的快速版本:

let headerFrame = CGRectMake(0, 0, 100, 1);
let tempView = UIView(frame: headerFrame);
tempView.backgroundColor = UIColor.clearColor()

let yourCustomView = CustomView(frame: headerFrame)
tempView.addSubview(yourCustomView)

self.tableView.tableHeaderView = tempView
于 2016-06-01T20:55:40.257 回答