使用自动布局,IB和字体大小时,表头视图高度是错误的

时间:2013-09-25 12:51:39

标签: ios objective-c uitableview autolayout

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

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

现在这与我的桌子完美配合。一切看起来都很棒。但是如果我用代码手动更改标题视图中的任何字体,布局会使视图变大,最终会在我的表格下面。

在设置字体和大小后,如何让tableviewcontroller为标题视图留下足够的空间?我希望我有理由解释这一点。

11 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:14)

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

当我这样做时,我会发现它会被一个部分标题遮挡。

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

答案 2 :(得分:9)

由于您的tableHeaderView状态为xib,并且具有自动布局,因此自定义headerViewsuperView的约束条件未知。您应该添加{{1}您的自定义constraints

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

viewDidLLoad

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

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

OK! PS:以下是相关文件:Resizing the View Controller’s Views

答案 3 :(得分:7)

解决了我的问题是:

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

我在某个地方找到了这个解决方案,并且像魅力一样工作,但我记不住在哪里了。

答案 4 :(得分:3)

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

答案 5 :(得分:1)

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

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

答案 6 :(得分:1)

结合@SwiftArchitect,@ vokilam和@mayqiyue的答案,并使用以编程方式创建的tableHeaderView代替笔尖(尽管如此,我不知道为什么它不应该工作使用nib),在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

答案 7 :(得分: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()

答案 8 :(得分:0)

@vokilam建议的

sizeHeaderToFit对我不起作用。

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

答案 9 :(得分: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;

}

答案 10 :(得分: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