在 tableHeaderView 中使用自动布局 [英] Using autolayout in a tableHeaderView

查看:52
本文介绍了在 tableHeaderView 中使用自动布局的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含多行 UILabelUIView 子类.此视图使用自动布局.

I have a UIView subclass that contains a multi-line UILabel. This view uses autolayout.

我想将此视图设置为 UITableViewtableHeaderView(不是节标题).此标题的高度将取决于标签的文本,而标签的文本又取决于设备的宽度.那种场景自动布局应该很擅长.

I would like to set this view as the tableHeaderView of a UITableView (not a section header). The height of this header will depend on the text of the label, which in turn depends on the width of the device. The sort of scenario autolayout should be great at.

我发现并尝试了许多 许多 解决方案来使这个工作,但无济于事.我尝试过的一些事情:

I have found and attempted many many solutions to get this working, but to no avail. Some of the things I've tried:

  • layoutSubviews
  • 期间在每个标签上设置一个preferredMaxLayoutWidth
  • 定义一个 intrinsicContentSize
  • 尝试确定视图所需的大小并手动设置 tableHeaderView 的框架.
  • 在设置标题时向视图添加宽度约束
  • 一堆其他的东西

我遇到的一些各种失败:

Some of the various failures I've encountered:

  • 标签超出了视图的宽度,不包裹
  • 框架的高度为 0
  • 应用程序崩溃并出现异常执行 -layoutSubviews 后仍需要自动布局

该解决方案(或解决方案,如有必要)应适用于 iOS 7 和 iOS 8.请注意,所有这些都是以编程方式完成的.我已经设置了一个 小型示例项目,以防您想对其进行破解以查看问题.我已将我的努力重新设置为以下起点:

The solution (or solutions, if necessary) should work for both iOS 7 and iOS 8. Note that all of this is being done programmatically. I've set up a small sample project in case you want to hack on it to see the issue. I've reset my efforts to the following start point:

SCAMessageView *header = [[SCAMessageView alloc] init];
header.titleLabel.text = @"Warning";
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.";
self.tableView.tableHeaderView = header;

我错过了什么?

推荐答案

到目前为止,我自己的最佳答案涉及设置 tableHeaderView 一次并强制布局传递.这允许测量所需的大小,然后我用它来设置标题的框架.而且,与 tableHeaderView 一样,我必须再次设置它以应用更改.

My own best answer so far involves setting the tableHeaderView once and forcing a layout pass. This allows a required size to be measured, which I then use to set the frame of the header. And, as is common with tableHeaderViews, I have to again set it a second time to apply the change.

- (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:

For multiline labels, this also relies on the custom view (the message view in this case) setting the preferredMaxLayoutWidth of each:

- (void)layoutSubviews
{
    [super layoutSubviews];

    self.titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.titleLabel.frame);
    self.subtitleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.subtitleLabel.frame);
}

2015 年 1 月更新

不幸的是,这似乎仍然是必要的.这是布局过程的快速版本:

Update January 2015

Unfortunately this still seems necessary. Here is a swift version of the layout process:

tableView.tableHeaderView = header
header.setNeedsLayout()
header.layoutIfNeeded()
let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
var frame = header.frame
frame.size.height = height
header.frame = frame
tableView.tableHeaderView = header

我发现将其移动到 UITableView 的扩展中很有用:

I've found it useful to move this into an extension on 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
        header.setNeedsLayout()
        header.layoutIfNeeded()
        let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
        var frame = header.frame
        frame.size.height = height
        header.frame = frame
        self.tableHeaderView = header
    }
}

用法:

let header = SCAMessageView()
header.titleLabel.text = "Warning"
header.subtitleLabel.text = "Warning message here."
tableView.setAndLayoutTableHeaderView(header)

这篇关于在 tableHeaderView 中使用自动布局的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆