我有一个包含多行< code>UILabel的< code>UIView子类。此视图使用自动布局。
我想将此视图设置为 UITable 视图的表标题视图
(而不是节标题)。此标头的高度将取决于标签的文本,而标签文本又取决于设备的宽度。自动布局的场景应该很棒。
我已经找到并尝试了许多解决方案来使其工作,但无济于事。我尝试了一些事情:
我遇到的一些失败:
执行后仍需要自动布局-layoutSubviews
解决方案(或解决方案,如果有必要)应该适用于iOS7和iOS8。请注意,所有这些都是以编程方式完成的。我已经设置了一个小示例项目,以防您想破解它来查看问题。我已经将我的工作重置为以下起点:
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;
我错过了什么?
以下 UITableView
扩展解决了表的自动布局和定位的所有常见问题标题视图
,而无需使用框架的旧版:
@implementation UITableView (AMHeaderView)
- (void)am_insertHeaderView:(UIView *)headerView
{
self.tableHeaderView = headerView;
NSLayoutConstraint *constraint =
[NSLayoutConstraint constraintWithItem: headerView
attribute: NSLayoutAttributeWidth
relatedBy: NSLayoutRelationEqual
toItem: headerView.superview
attribute: NSLayoutAttributeWidth
multiplier: 1.0
constant: 0.0];
[headerView.superview addConstraint:constraint];
[headerView layoutIfNeeded];
NSArray *constraints = headerView.constraints;
[headerView removeConstraints:constraints];
UIView *layoutView = [UIView new];
layoutView.translatesAutoresizingMaskIntoConstraints = NO;
[headerView insertSubview:layoutView atIndex:0];
[headerView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"|[view]|" options:0 metrics:nil views:@{@"view": layoutView}]];
[headerView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:nil views:@{@"view": layoutView}]];
[headerView addConstraints:constraints];
self.tableHeaderView = headerView;
[headerView layoutIfNeeded];
}
@end
“奇怪”步骤的解释:
>
首先,我们将标题视图宽度与表视图宽度联系起来:它有助于旋转,并防止标题视图的X居中子视图的深左移。
(魔术!)我们在HeaderView中插入假layoutView:此时我们强烈需要删除所有HeaderView约束,将layoutView扩展到HeaderView,然后恢复初始HeaderView约束。恰好约束的顺序有一定的意义!通过这种方式,我们得到了正确的HeaderView高度自动计算,也纠正了所有HeaderView子视图的
X中心化。
然后,我们只需要重新布局headerView,以获得正确的tableView
高度计算和headerView在截面上方的定位,而不相交。
附言。它也适用于iOS8。在一般情况下,这里不可能注释掉任何代码字符串。
对于仍在寻找解决方案的人来说,这是针对Swift 3的
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
}
}
要使用:
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()
}
}
要点是您应该让tableView
以与表视图单元格相同的方式管理tableHeaderView
的框架。这是通过tableView
的starinUpdate/endUpdate
完成的。
问题是tableView
在更新子帧时不关心AutoLayout。它使用当前tableHeaderView
的大小来确定第一个单元格/节标题应该在哪里。
1) 添加一个宽度约束,以便表标题视图
在调用布局时使用此宽度。还要添加 CenterX 和顶部约束,以使其相对于表视图
正确定位。
2)为了让tableView
知道tableHeaderView
的最新大小,例如,当设备旋转时,在viewDidLayoutSubview中,我们可以在tableHeaderView
上调用layoutIfNeed()。然后,如果大小发生变化,则调用startinUpdate/endUpdate。
请注意,我没有在一个函数中包含starinUpdate/endUpdate,因为我们可能希望将调用推迟到以后。
查看示例项目
到目前为止,我自己的最佳答案包括设置一次< code>tableHeaderView并强制一次布局传递。这允许测量所需的大小,然后我用它来设置标题的框架。和< code>tableHeaderView一样,我必须再次设置它才能应用更改。
- (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;
}
对于多行标签,这也依赖于自定义视图(在本例中为消息视图)设置每个标签的首选MaxLayoutWidth
:
- (void)layoutSubviews
{
[super layoutSubviews];
self.titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.titleLabel.frame);
self.subtitleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.subtitleLabel.frame);
}
不幸的是,这似乎仍然是必要的。以下是布局过程的快速版本:
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上的扩展中很有用:
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)
我有一个自定义视图CustomLayout(蓝色,自定义UIView),该视图包含3个子视图,通过使用约束(布局锚定)垂直对齐,每个视图按照以下顺序对齐: 1视图:幻灯片(红色,自定义UIView) 我想,当我单击按钮(黄色)时,如果使用动画打开,SlideLayout(红色)的高度大小会增加,如果关闭,则会减少。和其他视图必须在动画期间更改位置,如果SlideLayout增加/减少,则父视图(C
我正在深入研究自动布局,并试图了解如何水平居中多个视图,包括具有内在大小的视图(如UILabel或UIButton)。 例如,我有一个固定宽度为 320 的自定义视图。在其中,我有两个子视图,一个用户界面标签和一个用户界面图像视图。我希望 UI图像视图位于 UI标签右侧的 15 个像素,并且我希望 UI标签和 UI图像视图一起在超级视图中水平居中,但我不确定处理此问题的最佳方法。 我应该把它们放到
在我的UITableViewCell中,我有两个UIView堆叠在一起。让我们称之为顶部和底部。 俯视图对superview具有前导、尾随和顶部约束。它的高度约束为20。 底部视图对superview具有前导、尾随和底部约束。它的高度约束为20。 顶部和底部具有垂直约束。 以编程方式“隐藏”底部视图(并使顶部视图接触超级视图的底部)的最简单方法是什么?我不想再创建任何约束,因为我确实在情节提要中设
我花了两天时间尝试了混合和纯自动布局方法的各种解决方案,以实现在自动布局之前简单的滚动视图设置,现在它是正式的了——我一定太傻了。我主要是在故事板中设置这个(嗯,就是这样)。 所以我请求帮助。 视图树: 按钮应该水平滚动(从左到右,反之亦然)。有人能告诉我如何设置约束来使用纯自动布局实现这一点吗??? -- 我尝试了混合方法,如下所示: ...以及根据Apple的TechNote为< code>c
我想使用将我的jar上传到Maven中央存储库,并在其他项目中作为依赖项使用它。我遵循了这个不错的教程,结果我的JAR被上传到Sonatype Nexus(见下面的屏幕截图)。 我的jar的0.1版本可用;线路 在我的从属项目的文件。我通过点击屏幕截图中的关闭和释放按钮发布了0.1版本。之后,我评论了我在这里创建的Jira票据,并被告知中央同步将每两小时运行一次。 我的理解是,如果我现在想发布我的
你可能用过UIViewAutoresizingMask类型的一些常量,应用于当父视图改变尺寸的时候,相应UIView的frame也跟着更新的场景(通常用于横竖屏切换)。 在iOS6中,苹果介绍了自动排版机制,它和自动调整不同,并且更加复杂。 在Mac OS平台,CALayer有一个叫做layoutManager的属性可以通过CALayoutManager协议和CAConst