autoresizing是苹果早期的ui布局适配的解决办法,iOS6以前彻底能够胜任了,由于苹果手机只有3.5寸的屏幕,在加上手机app不多支持横屏,因此iOS开发者基本不用怎么适配布局,全部的ui控件只要相对父控件布局就能够了,没错autoResizing就是一个相对于父控件的布局解决方法;注意:它只能相对父控件布局;
***
在xcode中能够经过可视化的界面调整也能够经过代码去控制ios
在用autoResizing的时候须要关闭autoLayout和sizeclass(若是是用xcode6)
他们之间是互相冲突的正则表达式
能够经过图片看到autoResizing经过可视化能调整的只有6根线恰好和它的6个枚举值对应编程
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) { UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 << 0, UIViewAutoresizingFlexibleWidth = 1 << 1, UIViewAutoresizingFlexibleRightMargin = 1 << 2, UIViewAutoresizingFlexibleTopMargin = 1 << 3, UIViewAutoresizingFlexibleHeight = 1 << 4, UIViewAutoresizingFlexibleBottomMargin = 1 << 5 };
外边的4根线用来设置当前view距离父控件的上、下、左、右的距离是否固定;
内部的两根线来设置view是否跟随父控件来自适应width和height;
代码则能够经过view.autoresizingMask = ...来设定autoResizing值;
autoResizing的功能仅此而已;显然不够用;
***
举例:
1:让两个等宽等高的view之间的间距永远固定,如图的红色view和蓝色view,想让它们之间的距离固定经过autoResizing是不行的;由于autoResizing是相对父控件进行布局的,不能够在两个兄弟view之间创建布局关系;swift
能够看到一个横屏和竖屏就已经不能知足需求了,更别说屏幕尺寸还要变大
固然你有可能经过其余复杂的辅助手段实现,可是很麻烦;由于不只仅是横竖屏幕;屏幕尺寸也要变了;
autoResizing就到此为止,显然它已近过期,了解一下就能够了;
***xcode
作苹果开发的一个好处是有一个很好的东家,苹果公司,他不只很注重用户体验,并且还不忘为开发者去除一些没必要要的麻烦(例如:ARC的出现...)
autoLayout:能够在任意两个控件之间创建布局关系,能够是父子view也能够是兄弟view;功能强大了许多,固然学习成本也高了很多;
如图:
为了方便了解先勾选autoLayout就能够了,sizeclass先别勾了(若是是xcode6)
autoLayout的设置功能就上图中下方的红色方框中;
***app
左起第一个:iphone
经过图中红色框圈住的地方能够看出来,该处功能是设置多个view之间的对齐方式,因此设置的时候要同时选中多个View进行设置编程语言
第二个: ide
这一部分至关因而一个autoResizing,强大之处在于能够是任意两个view的相对布局,能够设置距离父控件的上下左右位置(红色框),还有自身的宽高,还能够相对其余控件设置宽高(蓝色框)函数
第三个:
这部分是用来添加、删除、和更新约束的,上半部分是对于选中view的约束更新,下边是容器中得全部view的约束
除了上边,还能够经过control按键配合拖线来作autoLayout,如图:
===
例子:用autolayout完成刚才autoResizing不能完成的任务,这里继续加大难度,除了让红色view和蓝色view等宽等高,并且距离始终保持不变之外,还要让两个view总体垂直居中于屏幕;先看最终的效果图
横屏效果
能够看到不论是横屏竖屏仍是大屏小屏,都是没问题的,到中分线的距离固定且相等;
***
下边开始一步一步经过autoLayout完成
第一步:
先让两个view等高等宽, 在xcode中同时选中红色view和蓝色view,勾选等宽,等高;这里也能够用另一种方式:按住control进行拖线,为了可读性和看着直观就不用了;
这时请注意看xcode得左上角,会有红色的箭头出现,表示添加的约束不完整,先说明:约束的完整性,一个view在视图中的位置相对固定(宽高和相对位置),那么约束就完整,注意是相对固定
; 而这里咱们只是让两个view等宽和等高,位置在哪里并无说明,约束固然不完整;因此有红色的错误;
知道红色的报错箭头正常以后,咱们继续,添加的每一条约束都是一个实体,能够在view中看到,点击每条约束能够在xcode的右侧编辑栏中看到约束的线性公式,这个线性公式正是苹果工程师的智慧结晶,巧妙的运用数学的智慧值得咱们去学习和体会;
顺着这几个文本框从上往下读能够获得以下的线性公式(Priority优先级不算入公式):view.width Equal view.width * 1 + 0
化解得:view.width = view.width
就这样实现了两个view之间的width关系的描述,将这个公式转化成代码应该很easy吧.. 哈哈
说明:这里咱们查看的是width约束,因此是view.width,两个view能够分别认为是红色view和蓝色view,能够相互对调位置
也许上边不三不四的公式很难理解,那么假设红色view的宽度为x, 蓝色view的宽度为y,对于任意两个实数x,y,均可以用下面的线性公式(或者说是一次线性函数)表示他们之间的关系:y = k·x + b
其中k是系数(就是上图中的Multipliter), b是常数(是上图中的Constant);
就是这个小学已经学习过的一次函数,能够知足任何两个view的任何边距关系;
第二步:
了解这些以后,回到正题,刚才只是添加了两个view等宽等高,接下来,为了保证不会错乱,咱们能够一个一个的来完成约束,这里先固定红色的view:
这里采用control拖线的方式:
这里咱们让红色view和蓝色的centerY到父view的centerY都是70,这样操做后至关于两个view在竖直方向上的位置固定;水平方向和每一个view的快高具体是多少都还没固定;因此xcode左上角继续报红色错误
第三步:
固定水平位置和宽高,这里固定宽高,只须要固定其中的一个便可,由于两个view的宽高相同;
能够看到添加完后红色的箭头变成了黄色,这表示,约束完整只差一步update了,这是你能够经过点击黄色箭头update或者如图:
好了,到此就搞定了;这个看似只有两个view,可是这个需求已是相对复杂了;
案例二:
经过上边的案例一能够看出autoLayout能够设置任意两个view之间的约束,能够说能实现任何想要布局;
下边的案例:让四个view始终等分屏幕:
效果图(为了说明效果,中间留了一个像素的间距):
思路:先固定好其中的一个,而后其余view和这个view等宽等高,而后设置相对父控件的约束;
每一条约束都是一个:NSLayoutConstraint对象
NSLayoutConstraint *layout = [NSLayoutConstraint constraintWithItem:(id) attribute:(NSLayoutAttribute) relatedBy:NSLayoutRelationEqual toItem:(id) attribute:(NSLayoutAttribute) multiplier:(CGFloat) constant:(CGFloat)]; [self.view addConstraint:layoutConstraint]
该方法正是刚才线性公式 y = k·x + b 的代码表示;因此虽然很长,可是很容易读懂;最后要记得把约束添加到view上,添加的时候必需要注意若是这个约束是父子view关系,约束必须加在父view上边;
可是用代码去实现autolayout实在是麻烦,刚才的两个例子,每一个例子中得约束有15个以上,若是用代码实现,要建立15个以上的NSLayoutConstraint对象,还有弄清楚关系,不能写错;苹果又为开发者考虑到了这一点;因而推出了为了写autolayout方便的VFL语言;
严格来说不算语言,一中语法相似正则表达式的专门用来写autolayout的;可是vfl并无带来简化,其繁琐程度基本上是写一行就不想写第二行的程度:
NSString *vfl1 = @"|-hPadding-[_headerL]-hPadding-|"; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl1 options:0 metrics:metrics views:dict1]];
和正则用法差很少,先用字符串写一些匹配规则,而后就调用后边的方法去解析这个规则到view上;我我的一直认为编程语言应该从简,将复杂的东西屏蔽掉,使咱们开发起来更高效,也有更多时间去处理好业务; 毕竟咱们天天作的情就是让用户简单起来,把复杂留给本身;因此vfl不用也罢;
与其说科技的发展,拉近了空间中任意两点的距离,让交流、信息传递更加便捷;倒不如说因为交流和信息传递的需求更加迫切而推进了科技的进步;大屏显然是一典型的例子,屏幕尺寸的相对增大,必定程度上方便了交流和信息传递,反之,相对小的屏幕对信息传递会有必定的局限;因此苹果推出大屏幕的手机也是人类进步的须要,并非什么跟风,扯淡结束;
屏幕大了,尺寸多了,带给开发者的天然是适配方面的工做量和思考;正如你们知道的那样;苹果是一家最具追求的公司,他固然会推出可行的解决方案就是sizeClass;
sizeClass: 对屏幕尺寸进行了抽象:不在拘泥于具体尺寸;由于尺寸一直都在变化,咱们若是按照尺寸去作适配,必定会很累的;
sizeClass针对iOS设备的屏幕进行了抽象分类:
- compact (紧凑-小)
- Any (任意)
- Regular (宽松-大)
总结几点:
把高度和宽度都抽象为上边的3种,3*3也就是总共9种类型;是9种类型,不是9种屏幕尺寸;
这样作的结果就是你能够作好一个interface builder适配,而后无论在iphone仍是ipad中均可以用了;
这就是苹果的意愿;打开xcode若是新建一个universal项目,在xcode6以前会默认有两个storyboard,一个是iphone的,一个是ipad版本的;xcode6以后只有一个,而且是正方形的,也就是说无论你作那种屏幕尺寸的app(不管是ipad仍是iphone),都只用这一个storyboard就能够了;
xcode中得样子:
***
具体来看:
图中9个格子表明 3*3的9中抽象;具体每种表明了那些含义能够选中看看;
好比iphone的竖屏它是这样抽象的:compact width * regular height
经过sizeclass对屏幕进行分类,而后用autolayout去适配布局,能够说能实现任何想要的效果,而且不用区分设备而作不一样的IB了,一个IB所有搞定,不论是iphone仍是ipad;
案例:
有个view
100 * 100
,在iphone竖屏时居于左上角,横屏时在右下角,ipad中在正中间;
像这种过去看来变态的要求,在如今来讲小菜一碟;
步骤一:处理竖屏状况
先用sizeclass固定屏幕为iphone竖屏:compact Width | Regular Height
而后添加view到ib上,用autolayout固定尺寸100 * 100;而且在左上角;这里让它居左20,居上20;
而后update frame便可
后边的同理解决,只不过要选对正确的sizeclass
***
iOS8加了sizeclass后,控件也多了个属性,在storyboard上托个label出来(以label为例),选中,在右边的菜单区域能够看到:installed,这个是用来控制改控件什么状况下显示,当前什么都没约束,表示Any * Any,就是不论是iphone什么尺寸仍是ipad什么尺寸均可以显示,点击左边的小加号+
能够用sizeclass控制什么状况显示;一样的还有字体、图片显示;
在不一样的屏幕下显示不一样的字体:
... 相似的功能还有不少
这个功能的思想和UIButton的三种状态(normal, highlighted, selected)相似,只不过这里有9种状态;
***
当屏幕种类变的愈来愈丰富的时候,若是要查看不一样屏幕之间的适配状况,在过去是要不停的切换模拟器,而后运行看效果的,而切换模拟器是很耗时的一件事;xcode6以后,咱们能够不用运行直接查看适配的状况;
对于刚才的事例进行如图操做便可不运行查看适配效果;
这两个属性是xcode6新出的特性
若是不是经过IB建立view,而是经过代码建立的View,如何在不运行程序的状况下实时的渲染在IB上呢,;@IBDesignable告诉Interface Builder这个类能够实时渲染到界面中,可是这个类必须是UIView或者NSView的子类。,便可在attribute inspector面板中可视化修改属性值。
示例(swift编写): 这个例子自定义一个UIView的子类,该子类拥有一个UIButton
@IBDesignable class MyCustomView: UIView { @IBInspectable var buttonTitleColor: UIColor! // button title color @IBInspectable var buttonTitle: String! // button title @IBInspectable var buttonFrame: CGRect! // button frame var myButton: UIButton! override init(frame: CGRect) { // init stored properties buttonTitleColor = UIColor.redColor() buttonTitle = "我是按钮" buttonFrame = CGRectMake(0, 0, 100, 50) myButton = UIButton(frame: buttonFrame) myButton.setTitleColor(buttonTitleColor, forState: .Normal) myButton.setTitle(buttonTitle, forState: .Normal) // call super initializer super.init(frame: frame) // add button to self addSubview(myButton) } required init(coder aDecoder: NSCoder) { // init stored properties buttonTitleColor = UIColor.redColor() buttonTitle = "button title" buttonFrame = CGRectMake(0, 0, 100, 50) myButton = UIButton(frame: buttonFrame) myButton.setTitleColor(buttonTitleColor, forState: .Normal) myButton.setTitle(buttonTitle, forState: .Normal) // call super initializer super.init(coder: aDecoder) // add button to self addSubview(myButton) } override func layoutSubviews() { // refresh button state through attribute inspector myButton.setTitleColor(buttonTitleColor, forState: .Normal) myButton.setTitle(buttonTitle, forState: .Normal) } }
该类在界面上加了一个Button,而且添加了三个属性,颜色、title、frame;这三个属性都是用来描述button的,,不用运行程序启动模拟器便可;
同时还重写drawRect方法画了一个矩形;
这个时候打开storyboard,添加一个View(为了控制gif图的大小,图中的View事先加好了约束,而且背景色改成蓝色,方便识别);修改class为MyCustomView;预览就会出现;同时咱们将开始画得矩形改成椭圆,而后再次查看storyBoard,预览已经变为椭圆,真是太爽了,不用在浪费时间等待模拟器启动去观察UI的布局了;
***