原文地址:http://www.pluto-y.com/wwdc-2015-mystries-of-auto-layout/
在WWDC 2015上关于AutoLayout这堂课上为程序员提供了一些福利般的新特性,并且对于一些技巧性的使用技能,对于程序猿在开发工作中的布局以及布局的调试打了许多鸡血啊,碰巧博主最近的项目也赶上了UI的替换,搞得博主都想现在就在项目中大展手脚的感觉。想想还有点小激动呢。
在WWDC 2015大会上,讲述了12个关于Auto Layout的技能点。如果英文不错的童鞋可以去查看WWDC上的视频:
* Mysteries Of Auto Layout Part1
* Mysteries Of Auto Layout Part2
各位童鞋,想知道这十二个技能点么?你特么来求我啊,来求我啊。求我我就告诉你。开始吧,跪下唱征服。
Stack View
是在iOS 9中推出的一个新的视图,对于程序猿来说是大大滴福利啊,不仅能使xib的可维护性增加而且由于其是轻量级的控件,也能保证程序运行流畅。其实这个视图有点像是Android里面的线性布局,不过它比线性布局好用,主要表现在他的属性方面。其中最常用的属性有4个,具体如下图:
* Axis(或Orientation在 OS X中):用于指明是水平线性布局还是垂直线性布局
* Alignment:用于指定Stack View
中子视图对其方式
* Distribution:用于指定子视图展示方式
* Spacing:用于指定子视图之间的间距
文字叙述可能有点繁琐,接下来看看苹果官方给我们提供的截图:
通过修改其中的属性可以将Stack View
中的子视图的布局进行自动排布(如果将线性布局从Horizontal
修改成Vertical
),而不需要通过修改Constraint进行修改布局。
另外在Interface Build
中提供了快速将几个视图添加到Stack View
的快捷按钮,只需通过选中所有的视图,并且点击该按钮即可。
如下图所示:
不仅能方便的将一些视图添加到Stack View
中,并且还有两个神奇的店,一是在已经建立好的的Stack View
可以插入新的视图,而不需要代码或者布局的调整,Stack View
会自动调整子视图的布局;二是Stack View
中如果将子视图进行隐藏的话,剩下的子视图会自动重新布局,如果加入动画的话,视图也会显示的非常友好和完美。而至于剩下的部分,就由小伙伴们自行探索了,我就不在这里讲解了。不理解的童鞋可以留言。
在WWDC2015大会上,官方里面是希望我们在修改约束的时候不需要在用Add或者Remove的方法进行修改约束,而是通过NSLayoutConstraint
中的activateConstraints
和deactivateConstraints
的方法进行修改约束,而通过该方法可以使您的程序运行更加流畅。
Note: 在用永远不要去调用
[NSLayoutConstraint deactivateConstraints:self.view.constraints];
方法,因为self.view中的约束不一定都是自己的约束,有可能会包含其他控件的约束。如果调用该方法可能会导致布局错乱。
而对于activateConstraints
和deactivateConstraints
方法来说同样可以添加到动画中,即可以通过Animations来缓慢的进行变化。
下面的做一个Demo试试看吧,首先进行简单的布局,并且先为视图初始化好基础的布局,并创建好对应的contraints。将视图在上方的约束都存在变量_topConstrains
中,而将视图移动到下方的约束都存在_bottomConstrains
,并给ViewController上添加一个点击事件,当点击时则将视图上下移动切换。而切换的代码如下:
/// self.view的点击事件
-(IBAction)kViewClick:(id)sender {
if ([_bottomConstrains.firstObject isActive]) {
[UIView animateWithDuration:3 animations:^{
[NSLayoutConstraint activateConstraints:_topConstrains];
[NSLayoutConstraint deactivateConstraints:_bottomConstrains];
[self.view layoutIfNeeded];
}];
} else {
[UIView animateWithDuration:3 animations:^{
[NSLayoutConstraint deactivateConstraints:_topConstrains];
[NSLayoutConstraint activateConstraints:_bottomConstrains];
[self.view layoutIfNeeded];
}];
}
}
对于这个博主暂时想不到这个技能点用什么卵用,不过既然WWDC上提到了,博主就稍微总结一下吧。博主查了一下,对于这个属性是在UIView (UIConstraintBasedLayoutLayering)
中声明的,而根据WWDC上的说法是有一些类的实例(如UILabel
和UIImage
)是有这个属性,这个博主就有点搞不清楚了。不过对于这个属性来说的话,其指的是真实内容的大小,而不是控件的大小,如下图中的UILabel
,控件的大小为蓝色区域的大小,而intrinsicContentSize
则是红色框左右的大小,其大小不跟随空间的大小而进行改变。如果用该大小去指定Label的话其实应该是最适合的大小,Label内部则不会有多余的空间。
另外对于intrinsicContentSize
是由系统产生的,而对于这个属性来说,如果在一些特殊的情况下要使用到这个变量的话(如要重写绘制控件方法时),程序员必须记得要对这个属性进行重写。至于其他的内容博主就不是很懂了,如果有哪位同学对这个属性比较了解其用法的话,麻烦留言给我。小生在此谢过了。
注意:要充分了解该方法所指代的内容,因为之后的技能点五中所提到的
Content Hugging Priority
与Content Compression Resistance Priority
是主要是针对该大小来说明的。
对于那些做过空间形式的留言或者是其他要求UITableViewCell的童鞋来说,要根据内容来Cell
高度是多么痛苦的一件事。记得当初笔者做一个类似朋友圈的功能,要做评论点赞图片等合为一体的Cell
,博主就高度这个Boss就整了好久才搞定的,没办法,小生不才,才刚出道。
而在这次的WWDC中,官方提供的技巧中就根据内容来调整Cell
的高度做了优化和讲解,让根据内容来调整高度变得异常的简单。
然后其实在WWDC之前网上已经有了关于如何产生自适应的UITableViewCell
的教程了,不过这次WWDC可能是起到总结的作用。具体的做法如下:
首先先正确适配Cell
中的约束,然后再需要变化的内容又或者说跟需要其内容进行调整高度的空间上(可能是一个或两个)进行添加Top Space to Container Margin
以及Bottom Space to Container Margin
,而这里的Container一般就是UITableViewCell
中的contentView
。添加好约束之后只需在代码中添加tableview.estimatedRowHeight = 60;tableview.rowHeight = UITableViewAutomaticDimension;
这两句代码即可,其中第一句设置Tableview
的Cell的估计高度。而第二句话也是必须的。
如果还是不懂如何进行设置的童鞋可以通过留言或者在微博上@叫什么都不如叫Pluto-Y找我索要Demo的代码。
关于优先级,此处所说的优先级主要是针对的是Content Hugging Priority
和Content Compression Resistance Priority
,通过利用这两个优先级可以让控件的大小是否被拉伸或者压缩。
其实从名字来上看就知道了Content Hugging Priority
是保证不被拉伸,而Content Compression Resistance Priority
主要是为了保证其不被压缩,当然这里的拉伸和压缩都是相对于技能点三种的intrinsicContentSize
来说的。简单来说的话,Content Hugging Priority
是用来阻止其变大的,如果用表达式来表示的话,该优先级的作用是用来使view.size <= max(intrinsicContentSize, view.frame.size)
。相反的,Content Compressiong Resistance Priority
是用来阻止其变小的,同样的用表达式来表示的话就是view.size >= min(intrinsicContentSize, view.frame.size)
,值得注意的是view.size指的是通过改变约束后控件的Size,而view.frame.size则是。而经过博主测试后发现如果在Contraints约束下且Priority为默认值的时候,可以分为两种情况:
* 如果intrinsicContentSize > view.frame.size
的情况下Content Compression Resistance Priority
才会请作用。
* 如果intrinsicContentSize < view.frame.size
的情况下Content Hugging Priority
才会请作用。
可以查看下图的Demo
情况1:
PS:图中的Label的水平方向上的Content Hugging Priority = 251
当view.frame.size.width > intrinsicContentSize.width
的情况下,设置Trailing Space
的优先级小于Content Hugging Priority
的情况下会使view.size.width = intrinsicContentSize.width
,而即使Content Compression Resistance Priority
设置成多大都没用。
情况2:
PS:图中的Label在水平方向上的Content Compression Resistance Priority = 750
当当view.frame.size.width < intrinsicContentSize.width
的情况下,设置Trailing Space
的优先级小于Content Compression Resistance Priority
的情况下会使view.size.width = intrinsicContentSize.width
,而即使Content Hugging Priority
设置成多大都没用。
而在WWDC15上举得例子是另一个,而在我的Demo代码中也有实现。
关于对齐方式在WWDC15上主要提到的就是两种方式需要注意,接下来我就用两点来给大家说说吧。
* 关于BaseLine
关于BaseLine来说除了之前系统中就有就有的Baseline
对齐来说,在iOS9中还添加了firstBaseline
和lastBaseline
的对齐,而这两个的对齐方式主要是针对文本的对其,例如Label、Button之类的控件。而想要知道这之间又是面区别的话,就看下面的两个简单的Demo:
第一个Demo是让一个Label的firstBaseline等于Button的firstBaseline,具体代码和效果图如下:
//_kBaseLineLabel是左边的Label,_kBaseLineBtn是右边的Button
NSLayoutConstraint *kContrains = [_kBaseLineLabel.firstBaselineAnchor constraintEqualToAnchor:_kBaseLineBtn.firstBaselineAnchor]; [NSLayoutConstraint activateConstraints:@[kContrains]];
效果图如下:
效果就是Label的第一行文字的下端与Button文字的下端对其。
第二个Demo是让Label的lastBaseline等于Button的lastBaseline,具体代码和效果图如下:
//_kBaseLineLabel是左边的Label,_kBaseLineBtn是右边的Button
NSLayoutConstraint *kContrains = [_kBaseLineLabel.lastBaselineAnchor constraintEqualToAnchor:_kBaseLineBtn.lastBaselineAnchor]; [NSLayoutConstraint activateConstraints:@[kContrains]];
效果图如下:
效果就是Label的最后一行文字的下端与Button文字的下端对其。而不管Label怎么变化,都会保证这两个控件文字的下端对其。这个在很多场景中都能用到。
关于这点很多人都会觉得Leading就是左对齐,而Trailing就是右对齐。这也是为什么博主不直接下左对齐右对齐而是写Leading和Trailing的意思。对于中文中当然Leading可以认为是左对齐,同理Trailing。毕竟中文是从左往右读的习惯。然后对于一些国家来说,他们的习惯是从右往左读,那么这么来说的话Leading就是右对齐,而Trailing就是左对齐了。所以WWDC中建议一定要用Leading和Trailing而不是用左对齐右对齐。当然在国内也有人用前边后边来表示Leading和Trailing,不过博主还是觉得没有Leading和Trailing来说更加能体现其中的精髓。
到此为止Part1就好了。还有下篇:WWDC 2015 - 揭开AutoLayout的神秘面纱(Mysteries Of Auto Layout) Part2。
而希望一次看到完整版的可以进入我的博客:http://www.pluto-y.com查看文章,并且文章中有Github的Demo下载地址,如果下载积分不够的童鞋可以去我博客里面找下载地址。
而CSDN的Demo下载地址为:Demo源码地址,该源码中包含了Part1和Part2的Demo。有不理解的可以进行留言。