标签:
autolayoutios开发xcodeui |
分类: Xcode/iOS/MacOS |
AutoLayout是什么?
使用一句Apple的官方定义的话
AutoLayout是一种基于约束的,描述性的布局系统。 Auto Layout Is a Constraint-Based, Descriptive Layout System.
关键词:
- 基于约束 - 和以往定义frame的位置和尺寸不同,AutoLayout的位置确定是以所谓相对位置的约束来定义的,比如x坐标为superView的中心,y坐标为屏幕底部上方10像素等
- 描述性 - 约束的定义和各个view的关系使用接近自然语言或者可视化语言(稍后会提到)的方法来进行描述
- 布局系统 - 即字面意思,用来负责界面的各个元素的位置。
总而言之,AutoLayout为开发者提供了一种不同于传统对于UI元素位置指定的布局方法。以前,不论是在IB里拖放,还是在代码中写,每个UIView都会有自己的frame属性,来定义其在当前视图中的位置和尺寸。使用AutoLayout的话,就变为了使用约束条件来定义view的位置和尺寸。这样的最大好处是一举解决了不同分辨率和屏幕尺寸下view的适配问题,另外也简化了旋转时view的位置的定义,原来在底部之上10像素居中的view,不论在旋转屏幕或是更换设备(iPad或者iPhone5或者以后可能出现的mini iPad)的时候,始终还在底部之上10像素居中的位置,不会发生变化。 总结
使用约束条件来描述布局,view的frame会依据这些约束来进行计算 Describe the layout with constraints, and frames are calculated automatically.
AutoLayout和Autoresizing Mask的区别
Autoresizing Mask是我们的老朋友了…如果你以前一直是代码写UI的话,你肯定写过UIViewAutoresizingFlexibleWidth之类的枚举;如果你以前用IB比较多的话,一定注意到过每个view的size inspector中都有一个红色线条的Autoresizing的指示器和相应的动画缩放的示意图,这就是Autoresizing Mask。在iOS6之前,关于屏幕旋转的适配和iPhone,iPad屏幕的自动适配,基本都是由Autoresizing Mask来完成的。但是随着大家对iOS app的要求越来越高,以及已经以及今后可能出现的多种屏幕和分辨率的设备来说,Autoresizing Mask显得有些落伍和迟钝了。AutoLayout可以完成所有原来Autoresizing Mask能完成的工作,同时还能够胜任一些原来无法完成的任务,其中包括:
- AutoLayout可以指定任意两个view的相对位置,而不需要像Autoresizing Mask那样需要两个view在直系的view hierarchy中。
- AutoLayout不必须指定相等关系的约束,它可以指定非相等约束(大于或者小于等);而Autoresizing Mask所能做的布局只能是相等条件的。
- AutoLayout可以指定约束的优先级,计算frame时将优先按照满足优先级高的条件进行计算。
总结
Autoresizing Mask是AutoLayout的子集,任何可以用Autoresizing Mask完成的工作都可以用AutoLayout完成。AutoLayout还具备一些Autoresizing Mask不具备的优良特性,以帮助我们更方便地构建界面。
AutoLayout基本使用方法
Interface Builder
手动使用API添加约束
创建
iOS6中新加入了一个类:NSLayoutConstraint,一个形如这样的约束
- item1.attribute = multiplier ? item2.attribute + constant
对应的代码为
1 |
[NSLayoutConstraint constraintWithItem:button |
2 |
attribute:NSLayoutAttributeBottom
|
3 |
relatedBy:NSLayoutRelationEqua
|
4 |
toItem:superview
|
5 |
attribute:NSLayoutAttributeBottom
|
6 |
multiplier:1.0
|
7 |
constant:-padding]
|
这对应的约束是“button的底部(y) = superview的底部 -10”。
添加
在创建约束之后,需要将其添加到作用的view上。UIView(当然NSView也一样)加入了一个新的实例方法:
- -(void)addConstraint:(NSLayoutConstraint *)constraint;
用来将约束添加到view。在添加时唯一要注意的是添加的目标view要遵循以下规则:
- 对于两个同层级view之间的约束关系,添加到他们的父view上
- 对于两个不同层级view之间的约束关系,添加到他们最近的共同父view上
- 对于有层次关系的两个view之间的约束关系,添加到层次较高的父view上
刷新
可以通过-setNeedsUpdateConstraints和-layoutIfNeeded两个方法来刷新约束的改变,使UIView重新布局。这和CoreGraphic的-setNeedsDisplay一套东西是一样的~
Visual Format Language 可视格式语言
UIKit团队这次相当有爱,估计他们自己也觉得新加约束的API名字太长了,因此他们发明了一种新的方式来描述约束条件,十分有趣。这种语言是对视觉描述的一种抽象,大概过程看起来是这样的: accept按钮在cancel按钮右侧默认间距处
最后使用VFL(Visual Format Language)描述变成这样:
1 |
[NSLayoutConstraint constraintsWithVisualFormat:@\\ "[cancelButton]-[acceptButton]\"
|
2 |
options:0
|
3 |
metrics:nil
|
4 |
views:viewsDictionary];
|
其中viewsDictionary是绑定了view的名字和对象的字典,对于这个例子可以用以下方法得到对应的字典:
1 |
UIButton *cancelButton = ... |
2 |
UIButton *acceptButton = ... |
3 |
viewsDictionary = NSDictionaryOfVariableBindings(cancelButton,acceptButton); |
生成的字典为
{ acceptButton = ""; cancelButton = ""; }
当然,不嫌累的话自己手写也未尝不可。现在字典啊数组啊写法相对简化了很多了,因此也不复杂。关于Objective-C的新语法,可以参考我之前的一篇WWDC 2012笔记:WWDC 2012 Session笔记——405 Modern Objective-C。 在view名字后面添加括号以及连接处的数字可以赋予表达式更多意义,以下进行一些举例:
- [cancelButton(72)]-12-[acceptButton(50)]
- 取消按钮宽72point,accept按钮宽50point,它们之间间距12point
- [wideView(>=60@700)]
- wideView宽度大于等于60point,该约束条件优先级为700(优先级最大值为1000,优先级越高的约束越先被满足)
- V:[redBox][yellowBox(==redBox)]
- 竖直布局,先是一个redBox,其下方紧接一个宽度等于redBox宽度的yellowBox
- H:|-[Find]-[FindNext]-[FindField(>=20)]-|
- 水平布局,Find距离父view左边缘默认间隔宽度,之后是FindNext距离Find间隔默认宽度;再之后是宽度不小于20的FindField,它和FindNext以及父view右边缘的间距都是默认宽度。(竖线'|‘ 表示superview的边缘)
容易出现的错误
因为涉及约束问题,因此约束模型下的所有可能出现的问题这里都会出现,具体来说包括两种:
- Ambiguous Layout 布局不能确定
- Unsatisfiable Constraints 无法满足约束
布局不能确定指的是给出的约束条件无法唯一确定一种布局,也即约束条件不足,无法得到唯一的布局结果。这种情况一般添加一些必要的约束或者调整优先级可以解决。无法满足约束的问题来源是有约束条件互相冲突,因此无法同时满足,需要删掉一些约束。两种错误在出现时均会导致布局的不稳定和错误,Ambiguous可以被容忍并且选择一种可行布局呈现在UI上,Unsatisfiable的话会无法得到UI布局并报错。 对于不能确定的布局,可以通过调试时暂停程序,在debugger中输入
- po [[UIWindow keyWindow] _autolayoutTrace]
来检查是否存在Ambiguous Layout以及存在的位置,来帮助添加条件。另外还有一些检查方法,来查看view的约束和约束状态:
- [view constraintsAffectingLayoutForOrientation/Axis: NSLayoutConstraintOrientationHorizontal/Vertical]
- [view hasAmbiguousLayout]
- [view exerciseAmbiguityInLayout]
布局动画
动画是UI体验的重要部分,更改布局以后的动画也非常关键。说到动画,Core Animation又立功了..自从CA出现以后,所有的动画效果都非常cheap,在auto layout中情况也和collection view里一样,很简单(可以参考WWDC 2012 Session笔记——219 Advanced Collection Views and Building Custom Layouts),只需要把layoutIfNeeded放到animation block中即可~
1 |
[UIView animateWithDuration:0.5 animations:^{ |
2 |
[view layoutIfNeeded];
|
3 |
}]; |
部分代码
纯净代码UI正常布局后,添加autolayout就可以了,调整相当方便
//-----autoLayout
[_btn_1 setTranslatesAutoresizingMaskIntoConstraints:NO];
[_btn_2 setTranslatesAutoresizingMaskIntoConstraints:NO];
[_btn_3 setTranslatesAutoresizingMaskIntoConstraints:NO];
[_btn_4 setTranslatesAutoresizingMaskIntoConstraints:NO];
CGSize winSize = [[iHappySDKSingle shareSingle] getScreenSize];
CGFloat tpo = _btn_1.frame.origin.y;
CGFloat hpod = _btn_1.frame.origin.x;
CGFloat btnH = _btn_1.frame.size.height;
CGFloat vpod = winSize.width*0.15-btnH;
NSNumber* tp = [NSNumber numberWithFloat:tpo];
NSNumber* hd = [NSNumber numberWithFloat:hpod];
NSNumber* vd = [NSNumber numberWithFloat:vpod];
NSNumber* bh = [NSNumber numberWithFloat:btnH];
NSNumber* btm = [NSNumber numberWithFloat:vpod*2];
NSDictionary *dict1 = NSDictionaryOfVariableBindings(_btn_1,_btn_2,_btn_3,_btn_4);
NSDictionary *metrics =@{@"hPadding":hd,@"vPadding":vd,@"top":tp,@"btm":btm,@"btnHeight":bh};
NSString *vfl1 = @"|-hPadding-[_btn_1]-hPadding-|";
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl1
options:0
metrics:metrics
views:dict1]];
NSString *vfl2 = @"|-hPadding-[_btn_2]-hPadding-|";
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl2
options:0
metrics:metrics
views:dict1]];
NSString *vfl3 = @"|-hPadding-[_btn_3]-hPadding-|";
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl3
options:0
metrics:metrics
views:dict1]];
NSString *vfl4 = @"|-hPadding-[_btn_4]-hPadding-|";
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl4
options:0
metrics:metrics
views:dict1]];
NSString *vfl5 = @"V:|-(<=top)-[_btn_1(btnHeight)]-vPadding-[_btn_2(btnHeight)]-vPadding-[_btn_3(btnHeight)]-vPadding-[_btn_4(btnHeight)]-(>=btm)-|";
if (_btn_1.hidden) {
vfl5 = @"V:|-(<=top)-[_btn_2(btnHeight)]-vPadding-[_btn_3(btnHeight)]-vPadding-[_btn_4(btnHeight)]-(>=btm)-|";
}
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl5
options:0
metrics:metrics
views:dict1]];
- (void)setAutoLayoutForKuang:(UIView*)imgv
{
UIView * view = self;
[imgv setTranslatesAutoresizingMaskIntoConstraints:NO];
NSDictionary *dict1 = NSDictionaryOfVariableBindings(imgv);
NSDictionary *metrics = @{@"width":[NSNumber numberWithFloat:imgv.frame.size.width],
@"height":[NSNumber numberWithFloat:imgv.frame.size.height],
@"top":[NSNumber numberWithFloat:imgv.frame.origin.y]
};
NSString *vfl1 = @"[imgv(width)]";
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl1
options:0
metrics:metrics
views:dict1]];
NSString *vfl2 = @"V:[imgv(height)]";
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl2
options:0
metrics:metrics
views:dict1]];
[view addConstraint:[NSLayoutConstraint constraintWithItem:imgvattribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:viewattribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[view addConstraint:[NSLayoutConstraint constraintWithItem:imgvattribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:viewattribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
//animation
[UIView animateWithDuration:0.25 animations:^{
[imgv layoutIfNeeded];
}];
}
iOS开发 多屏尺的自动适配(转)的更多相关文章
-
【iOS开发】多屏尺的自动适配 AutoLayout (纯代码方式)
关于AutoLayout,最早从iOS6开始引入使用. 主要功能是使用约束,对视图进行相对布局,以适应不同屏尺的变换. 网上大量的资料都在介绍xib和storyboard,如何使用AutoLa ...
-
iOS开发:iPhone6、6 plus适配
本文转载至 http://jingyan.baidu.com/article/8cdccae97a5c2b315413cda9.html 1 2 3 4 5 6 7 分步阅读 随着苹果公司持续推出新产 ...
-
iOS开发——锁屏监听
公司所做的项目,锁屏监听是为了60秒后,解锁瓶后显示[手势解锁]或[指纹验证]: 第一步:AppDelegate.m 头部导入 #import <notify.h> #define Not ...
-
iOS开发进阶 - 使用shell脚本自动打包上传到fir.im上-b
用fir.im测试已经好长时间了,感觉每次打包上传都很麻烦,想着是不是可以用脚本自动打包,在网上搜了一下确实有,下面总结一下如何使用脚本自动打包上传到fir.im,以及打包过程中遇到的问题和解决办法 ...
-
IOS开发学习笔记036-UIScrollView-循环自动滚动
实现scrollView的自动循环滚动,需要实现几个方法. 其中scrollView中始终保存三张图片,其他的图片在滚动到时再进行加载. 循环的实现主要是在setUpdate 中,如果索引为0是第一个 ...
-
在iOS 开发中用GDataXML(DOM方式)解析xml文件
因为GDataXML的内部实现是通过DOM方式解析的,而在iOS 开发中用DOM方式解析xml文件,这个时候我们需要开启DOM,因为ios 开发中是不会自动开启的,只有在mac 开发中才自动开启的.我 ...
-
iOS 随笔小技巧 弱self 打印当前类行数列数,多人开发自动适配pch地址,获取设备uid的信息
$(SRCROOT)/PrefixHeader.pch自动适配pch地址 __weak __block typeof(self) weakself = self; __weak typeof(self ...
-
IOS开发之绝对布局和相对布局(屏幕适配)
之前如果做过Web前端页面的小伙伴们,看到绝对定位和相对定位并不陌生,并且使用起来也挺方便.在IOS的UI设计中也有绝对定位和相对定位,和我们的web前端的绝对定位和相对定位有所不同但又有相似之处.下 ...
-
iOS开发笔记10:圆点缩放动画、强制更新、远程推送加语音提醒及UIView截屏
1.使用CAReplicatorLayer制作等待动画 CALayer+CABasicAnimation可以制作很多简单的动画效果,之前的博客中介绍的“两个动画”,一个是利用一张渐变色图片+CABas ...
随机推荐
-
【Java 进阶篇】【第一课】String类
引用 String类包含在java.lang包中.这个包会在Java启动的时候自动import,所以可以当做一个内置类(built-in class).我们不需要显式的使用import引入String ...
-
android下调试unity3d应用
原地址:http://blog.csdn.net/armoonwei/article/details/7032455 目前貌似不支持断点调试,但可以通过日志打印(logcat)来跟踪. 在androi ...
-
【UVA12093】Protecting Zonk (树形DP)
题意: 给定一个有n个节点的无根树,有两种装置A和B,每种都有无限多个.在某个节点X使用A装置需要C1的花费,并且此时与节点X相连的边都被覆盖.在某个节点X使用B装置需要C2的花费,并且此时与节点X相 ...
-
ado.net数据库操作(1)
这些都是网上搜索到的,我把他放在自己的博客里,作为笔记 1.1创建数据库连接(sqlserver) <%@ Import Namespace="System.Data" %& ...
-
MySQL学习(二)索引与锁 --- 2019年1月
1.Order By 是怎么工作的 MySQL做排序是一个成本比较高的操作.MySQL会为每个线程分配一个 sort_buffer 内存用于排序,该内存大小为 sort_buffer_size. 全字 ...
-
全球各大邮件SMTP服务限制
常用免费SMTP服务的发送限制,转贴 GMail 免费邮箱 http://gmail.google.comSMTP 服务器:smtp.gmail.com策略:发送延时 0,每天发送量限制 50(GMa ...
-
初次实践数据库--SQL Server2016
初学数据库使用 安装了SQL Server2016的开发者版本,本来以为就可以愉快地开始数据库的挖坑了,发现开出来之后除了创建数据库.选择数据库以外,并没有什么操作. 后来才发现还需要再安装SSMS( ...
-
【Cf #292 D】Drazil and Morning Exercise(树的直径,树上差分)
有一个经典的问题存在于这个子问题里,就是求出每个点到其他点的最远距离. 这个问题和树的直径有很大的关系,因为事实上距离每个点最远的点一定是直径的两个端点.所以我们可以很容易地进行$3$遍$Dfs$就可 ...
-
DB2 日志
跟Oracle类似DB2也分为两个模式,日志循环vs归档日志,也就是非归档和归档模式,下面对这两种模式做简单的介绍. 日志循环 日志循环是默认方式,也就是非归档模式,这种模式只支持backup off ...
-
mui 的注意事项点
1.mui的subpage在微信浏览器中不能正常工作. 2.MUI支持json格式解析: 调用JSON.parse(data)或者JSON.stringify(data); 3.