![](http://file.zhishichong.com/images/article/20161028/43e260dfb3f7d3c98f0ead889e3189d6.jpg)
主要记录自己在使用Autolayout
做项目的时候所遇到的问题以及解决方案,对于同一个问题往往存在多种解决方式,我的方式或许存在很多需要优化的地方,如您有更佳的方案,请给我留言哦!谢谢!
本文涉及内容:
1.Autolayout与UIScrollView
2.AutoLayout与UITableViewCell
Autolayout与UIScrollView
这个问题主要是做《仿简书》首页的时候遇到的,当时需要在一个ScrollView
里需要放多个大小不固定的Label
,发现控件位置总是出错。最后我发现ScrollView
相对于普通View
存在一些区别:平时我们布局,子视图会依赖父视图来拉约束,但是ScrollView
的contentSize
的大小是由其subview
的大小来决定的,如果我们子视图继续依赖ScrollView
来拉约束,那么就会形成相互依赖,位置无法确定。
那么怎么解决呢?当时的解决方式是:Scrollview
里面放一个ContainView
,然后子视图拉约束到ContainView
,这样ContainView
的大小就可以根据子视图来变化,Scrollview
的大小根据ContainView
来定。
仍然需要遵守的两大原则:
scrollView
内部子控件的尺寸不能以scrollView
的尺寸为参照scrollView
内部的子控件的约束必须完整(子控件在水平和垂直方向用约束把ContainView
撑满,使containtView
扩展以适合它们的尺寸。例如:以前普通布局,只需要定义宽高、左、上的距离即可,但是这时候需要把下、右的距离也补上,不然containView
不知道到底尺寸多大)
动手实践:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
var topScroll: UIScrollView! var topContainerView = UIView() func setTopScroll(){ topScroll = UIScrollView() addSubview(topScroll) topScroll.snp_makeConstraints { (make) -> Void in make.top.equalTo(0) make.height.equalTo(topScrollHeight) //topScrollHeigh为固定值 make.left.right.equalTo(self) } topScroll.addSubview(topContainerView) topContainerView.snp_makeConstraints { (make) -> Void in make.edges.equalTo(topScroll) make.height.equalTo(topScrollHeight) //topScrollHeigh为固定值 } for idx in 0.. Void in make.height.equalTo(topContainerView) if idx > 0, let previousLabel = topScroll.subviews[0].subviews[idx - 1] as? UILabel { make.left.equalTo(previousLabel.snp_right).offset(labelGapX * 2) } else { make.left.equalTo(labelGapX) //labelGapX为固定值 } }) if idx == themeArr.count - 1 { topContainerView.snp_makeConstraints(closure: { (make) -> Void in make.right.equalTo(label) }) } } } } |
上述代码中垂直方向高度为固定,那么水平方向就值得注意,下面这句话代码是关键,可以确定topContainerView
的具体大小,进而确定scrollView
的大小,也正是符合我们刚阐述的两大原则
1 2 |
topContainerView.snp_makeConstraints(closure: { (make) -> Void in make.right.equalTo(label) |
AutoLayout与UITableViewCell
我目前遇到的UITableViewCell
主要分为三类:
UITableviewCell
中的子控件大小确定,那么也就是说UITableviewCell
的高度、宽度可以确定,这样的cell
子控件完全可以依赖UITableviewCell
来进行布局。UITableviewCell
的高度为可变的。那么我们可以采取上面阐述的方法,子控件依赖ContentView
来布局,与ScrollView
类似。- 第三类是第二类的升级版,
UITableviewCell
的子控件会根据需要出现或消失
下面主要讲我是怎么处理第三种情况的,示例图如下(简书的简友动态页面):
对于动态UITableViewCell
,我们需要让Cell
的子控件把约束固定到ContentView
上,而且要约束完整。但是简友动态还有一个问题就是高度可变(子View
有时候需要隐藏),采取的解决方案是:对约束增加优先级的差异,对单条Constraint
进行active
和deactive
操作,那么意味着可以动态的启用或者禁用某条预置的约束。所以我们只要预先设置一条高优先级的高度为0(或者宽度为0)的约束 然后在适当的时候激活它就可以了。
动手实践:
为了代码简洁只写重点部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
sourceUserLabel = UILabel() sourceUserLabel.sizeToFit() contentView.addSubview(sourceUserLabel) sourceUserLabel.snp_makeConstraints { (make) -> Void in make.top.equalTo(contentView).offset(30) make.left.equalTo(contentView).offset(20) } eventLabel = UILabel() eventLabel.sizeToFit() contentView.addSubview(eventLabel) eventLabel.snp_makeConstraints { (make) -> Void in make.left.equalTo(sourceUserLabel) make.top.equalTo(sourceUserLabel.snp_bottom).offset(10) } |
这段代码只是设置了用户名和event
类型(发布文字、喜欢之类) ,可以看出来只是设置了左、上的距离,以及SizeToFit
,也就是设置了高度和宽度,但是并没有把ContentView
撑满,继续
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
containView = UIView() containView.backgroundColor = UIColor.redColor() contentView.addSubview(containView) containView.snp_makeConstraints { (make) -> Void in make.top.equalTo(eventLabel.snp_bottom).offset(10) make.left.equalTo(contentView).offset(10) make.right.equalTo(contentView).offset(-20) } contentLabel = UILabel() contentLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping contentLabel.font = UIFont.systemFontOfSize(18) contentLabel.numberOfLines = 3 contentLabel.sizeToFit() containView.addSubview(contentLabel) contentLabel.snp_makeConstraints { (make) -> Void in make.edges.equalTo(containView).inset(UIEdgeInsetsMake(10, 10, 10, 10)).priorityHigh() } |
这个是要把评论内容的Label
放到了一个superView
中,也就是ContainView
中,然后ContainView
的尺寸根据内部Label
的尺寸来变化,所以Label
约束也要满足“撑满”ContainView
。make.edges.equalTo(containView).inset(UIEdgeInsetsMake(10, 10, 10, 10)).priorityHigh()
与SizetoFit
结合就可以约束完整,确定ContainView
的尺寸。注意PriorityHigh
是设置约束优先级为750,默认为1000。
1 2 3 4 5 |
containView.snp_makeConstraints { (make) -> Void in self.heightContraint = make.height.equalTo(0).constraint make.bottom.equalTo(contentView).offset(-10) self.heightContraint?.deactivate() } |
这段代码有关键作用,make.bottom.equalTo(contentView).offset(-10)
来达到约束完整的目的,“撑满”ContentView
来确定具体尺寸。同时设置了 self.heightContraint = make.height.equalTo(0).constraint
来使containView
的告诉为0,约束优先级为1000.那么就是说当此约束activate()
的时候,containView
高度为零,隐藏。当deactivate()
的时候,会使用优先级为750的约束来确定ContainView
的高度。
1 2 3 4 5 6 7 8 9 10 |
func cellType(bool: Bool){ if bool{ self.heightContraint?.activate() } else{ self.heightContraint?.deactivate() } } |