ios 使用自动布局、IB 和字体大小时,表格标题视图高度错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19005446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:41:11  来源:igfitidea点击:

table header view height is wrong when using auto layout, IB, and font sizes

iosobjective-cuitableviewautolayout

提问by jedipixel

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.

我正在尝试为我的 uiTableView 创建一个标题视图(不是节标题,我已经有了。)我在界面构建器中设置了一个 XIB。所有的连接都已连接好,运行起来很漂亮……除了桌子没有给它足够的空间!我的问题是表格的顶部与表格的标题重叠了一点。

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.

我的 XIB 为所有按钮设置了自动布局,IB 很高兴约束不冲突/不明确。视图设置为自由尺寸,在我的情况下最终为 320 x 471。然后在视图的约束中,我为相同的视图设置了固有大小。

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.

任何想法如何在设置字体和大小后让 tableviewcontroller 为标题视图留出足够的空间?我希望我已经解释了这一点。

回答by vokilam

Note: A Swift 3+ version can be found here: https://gist.github.com/marcoarment/1105553afba6b4900c10#gistcomment-1933639

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



The idea is to calculate header's height with help of systemLayoutSizeFittingSize:targetSize.

这个想法是在 的帮助下计算标题的高度systemLayoutSizeFittingSize:targetSize

Returns the size of the view that satisfies the constraints it holds. Determines the best size of the view considering all constraints it holds and those of its subviews.

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

After changing header's height it is necessary to reassign tableHeaderViewproperty to adjust table cells.

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

Based on this answer: Using Auto Layout in UITableView for dynamic cell layouts & variable row heights

基于这个答案: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;
}

回答by rmigneco

I encountered a similar problem when I was trying to set my table view header to a custom view I defined with auto layout using interface builder.

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

When I did so, I would find that it would be obscured by a section header.

当我这样做时,我会发现它会被节标题遮挡。

My work around involved using a "dummy view" as the table header view and then adding my custom view to that dummy view as a subview. I think this allows auto layout to configure the appearance as per the constraints and the containing view's frame. This is probably not as elegant as vokilam's solution, but it works for me.

我的工作涉及使用“虚拟视图”作为表标题视图,然后将我的自定义视图作为子视图添加到该虚拟视图中。我认为这允许自动布局根据约束和包含视图的框架配置外观。这可能不像 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;

回答by mayqiyue

Because your tableHeaderViewis inited form xibwith auto layout, so the constraints of your custom headerViewand the superViewis unknown.You should add the constraintsof your custom headerView:

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

1.in viewDidLLoadassign your custom headerView to the tableView's tableHeaderView

1.在viewDidLLoad将您的自定义 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,add the essential constraints of your custom headerView

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

OK! PS:Here is the related document:Resizing the View Controller's Views

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

回答by ClockWise

What solved my issue was this:

什么解决了我的问题是这样的:

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

I found this solution somewhere and worked like charm, I can't remember where though.

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

回答by Mr Rogers

I found vokilam's answer to work great. Here's his solution in Swift.

我发现 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
}

回答by Vitaliy Gozhenko

In my case systemLayoutSizeFittingSizereturn incorrect size, because one of the subviews use aspect ratio (width to height) 4:1 constraint.

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

After I change it to constant height constraint value (100), it begin to works as expected.

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

回答by Evan R

Combining answers by @SwiftArchitect, @vokilam, and @mayqiyue, and using a programmatically created tableHeaderViewinstead of a nib (although, I don't see any reason why it shouldn't work with a nib), and under iOS 10.x/Xcode 8.2.1, here is what I have working:

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

Create the view in your view controller's -viewDidLoador -initmethods, or wherever you're using the table view:

在视图控制器的-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

Wherever you set up your custom header view's constraints (could be in `updateConstraints but this method could be called multiple times):

无论您在何处设置自定义标题视图的约束(可以在 `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

回答by templeman15

The other answers pointed me in the right direction for getting the tableHeaderView to resize appropriately. However, I was getting a gap between the header and the tableView cells. This could also cause your cells to overlap with your header, depending on if the header grew or got smaller.

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

I went from this:

我从这个出发:

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

To fix the gap/overlap all I had to do was move tableView.reloadData() to after I set the new height instead of before.

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

To this:

对此:

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

回答by SwiftArchitect

sizeHeaderToFitsuggested by @vokilam didn't work for me.

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

What worked is a modified version of @mayqiyue, invoked during viewDidLoad, wired height, equal width to table view.

有效的是@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]];

回答by iosDeveloper

Below code has worked for me :- Add this in your UIView class -

下面的代码对我有用:- 在你的 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;

}

}