Ben*_*ard 16 uitableview uiview ios autolayout nslayoutconstraint
我有一个UIView
包含多行的子类UILabel
.此视图使用autolayout.
我想设置该视图为tableHeaderView
的UITableView
(不是一节头).此标题的高度取决于标签的文本,而标签的文本又取决于设备的宽度.那种场景自动布局应该很棒.
我发现并尝试了 许多 解决方案来实现这一点,但无济于事.我试过的一些事情:
preferredMaxLayoutWidth
在期间为每个标签设置一个layoutSubviews
intrinsicContentSize
tableHeaderView
手动设置框架.我遇到的一些各种失败:
Auto Layout still required after executing -layoutSubviews
解决方案(或解决方案,如有必要)应适用于iOS 7和iOS 8.请注意,所有这些都是以编程方式完成的.我已经设置了一个小型示例项目,以防您想要查看问题.我已将我的努力重置到以下起点:
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;
Run Code Online (Sandbox Code Playgroud)
我错过了什么?
Ben*_*ard 21
到目前为止,我自己的最佳答案涉及设置tableHeaderView
一次并强制布局传递.这允许测量所需的大小,然后我用它来设置标题的框架.并且,与tableHeaderView
s一样,我必须再次设置它以应用更改.
- (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;
}
Run Code Online (Sandbox Code Playgroud)
对于多行标签,这也依赖于自定义视图(在本例中为消息视图)设置preferredMaxLayoutWidth
每个标签:
- (void)layoutSubviews
{
[super layoutSubviews];
self.titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.titleLabel.frame);
self.subtitleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.subtitleLabel.frame);
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,这仍然是必要的 这是布局过程的一个快速版本:
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
Run Code Online (Sandbox Code Playgroud)
我发现将它移动到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
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
let header = SCAMessageView()
header.titleLabel.text = "Warning"
header.subtitleLabel.text = "Warning message here."
tableView.setAndLayoutTableHeaderView(header)
Run Code Online (Sandbox Code Playgroud)
对于仍在寻找解决方案的人来说,这适用于Swift 3和iOS 9+.这是仅使用AutoLayout的一个.它还可以在设备旋转时正确更新.
extension UITableView {
// 1.
func setTableHeaderView(headerView: UIView) {
headerView.translatesAutoresizingMaskIntoConstraints = false
self.tableHeaderView = headerView
// ** Must setup AutoLayout after set tableHeaderView.
headerView.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
headerView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
headerView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
}
// 2.
func shouldUpdateHeaderViewFrame() -> Bool {
guard let headerView = self.tableHeaderView else { return false }
let oldSize = headerView.bounds.size
// Update the size
headerView.layoutIfNeeded()
let newSize = headerView.bounds.size
return oldSize != newSize
}
}
Run Code Online (Sandbox Code Playgroud)
使用:
override func viewDidLoad() {
...
// 1.
self.tableView.setTableHeaderView(headerView: customView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// 2. Reflect the latest size in tableHeaderView
if self.tableView.shouldUpdateHeaderViewFrame() {
// **This is where table view's content (tableHeaderView, section headers, cells)
// frames are updated to account for the new table header size.
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
}
Run Code Online (Sandbox Code Playgroud)
要点是,您应该以与表格视图单元格相同的方式tableView
管理框架tableHeaderView
.这是通过tableView
's 完成的beginUpdates/endUpdates
.
事情是tableView
它更新子帧时不关心AutoLayout.它使用当前 tableHeaderView
的大小来确定第一个单元/节头应该在哪里.
1)添加宽度约束,以便tableHeaderView
在调用layoutIfNeeded()时使用此宽度.同时添加centerX和top限制以相对于它正确定位它tableView
.
2)为了让人tableView
知道最新的大小tableHeaderView
,例如,当设备被旋转时,在viewDidLayoutSubviews中我们可以调用layoutIfNeeded()tableHeaderView
.然后,如果更改了大小,请调用beginUpdates/endUpdates.
请注意,我没有在一个函数中包含beginUpdates/endUpdates,因为我们可能希望稍后将调用推迟.
归档时间: |
|
查看次数: |
12448 次 |
最近记录: |