Autoresizing

Autoresizing

Autoresizing是早期iOS设备机型很少、APP界面布局相对简单的背景下产生的一种屏幕适配技术。早期的iOS设备机型很少、屏幕尺寸单一、APP界面相对简单,屏幕适配并没有现在这么复杂,在当时这种背景下,产生了Autoresizing。当时这种情况下苹果推出Autoresizing也是可以理解的,但是如果放到现在这种大背景下,Autoresizing是不能够满足开发者的屏幕适配需求的,具体原因请见下文。

1.1.Autoresizing的启用

Xcode5之后,新建的项目默认使用AutoLayout。Autoresizing默认不启用,我们可以去掉use Auto Layout前面的对勾来启用Autoresizing,如下图。

image

Xcode8中删除了size class选项,取而代之的是Use Trait Variations(特征变量)选项。

1.2.Autoresizing介绍

有一种说法:autoresizing是为了解决iPad开发中横竖屏适配问题应运而生的。代码中的autoresizingMask和storyBoard中尺寸检查器中的Autoresizing是一回事。iPhone5开始,Xcode添加了autolayout功能。storyBoard默认采用autolayout,取代了之前的autoresizing。如果使用autoresizing,需要在以下位置去掉“Use Auto Layout”。

1.2.1.storyboard中使用Autoresizing

image

从上图看出,storyBoard中的的Autoresizing只能设置两个父子视图之间的相对位置关系,一共6条虚线,分别是周围的四条虚线和方块内部的两条线。周围的四条虚线分别代表子控件距离父控件上、下、左、右之间的距离关系/或者叫约束关系,周围的四条虚线所包围的小方块代表子视图,小方块内部的两条带双向箭头的线分别代表子控件的宽度和高度。
当我们点击周围四条虚线时,虚线会变成实线,代表子控件和父控件在这个方向上的间距被固定了。当我们点击子视图内部的虚线时,同样也变为实线,代表子视图的宽度或者高度被固定了。
举个例子:当我们点击最左边的虚线时候,代表子视图距离父视图左边的间距被固定了,而其他三个方向的距离和宽高会随父视图的缩放二缩放。

1.2.2.代码中使用Autoresizing

我们不仅可以在storyboard中使用Autoresizing来约束父子视图,也可以使用代码来设置父子视图之间的位置关系。UIView有一个autoresizingMask属性,可以通过该属性来约束父子视图之前的位置关系,并且UIView还有一个BOOL类型的autoresizesSubviews属性,默认为YES,代表父控件会跟随子控件尺寸的变化而变化。和frame、bounds、center、transform等属性一样,autoresizingMask和autoresizesSubviews也是属于UIView的几何分类-UIViewGeometry中的属性。

@property(nonatomic) BOOL autoresizesSubviews; // default is YES. if set, subviews are adjusted according to their autoresizingMask if self.bounds changes
@property(nonatomic) UIViewAutoresizing autoresizingMask; // simple resize. default is UIViewAutoresizingNone

查看注释,autoresizesSubviews属性的大意是:默认autoresizesSubviews = YES。如果UIView设置了autoresizesSubviews,那么他的子控件的bounds如果发生了变化,他的子控件将会根据子控件自己的autoresizingMask属性的值来进行调整。
那么autoresizingMask又是什么呢?
autoresizingMask是一个枚举值,作用是自动调整子控件与父控件中间的margin(间距)或者子控件的宽高。默认其枚举值是UIViewAutoresizingNone。如下是其全部的枚举值:

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
};

从上面给出的代码可以看出,autoresizingMask有7个枚举值,除了UIViewAutoresizingNone之外还有6个枚举值,分别对应storyboard中的那6条虚线。所以,storyboard和代码是相同的,无论什么视图,凡是可以通过storyboard进行设置的属性,都有与之对应的属性代码,我们也可以使用代码的方式实现。毕竟,storyboard中的属性最终还是会翻译成可执行的代码,只不过XCode利用可视化的storyboard工具帮助我们完成了代码完成的事情。
值得注意的是:autoresizingMask的枚举值是使用位移的形式给出的,这样设置的好处在于,当我们使用代码给某个视图设置autoresizingMask属性时,我们可以给autoresizingMask属性指定多个枚举值。指定方式如下:

[subView setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin | 
![7.gif](http://upload-images.jianshu.io/upload_images/1055199-b48a0ccf7076c294.gif?imageMogr2/auto-orient/strip)
FlexibleLeftMargin];

甚至我们可以使用这种方式:

[subView setAutoresizingMask:5]; 

系统自动把5分解成5 = 4 + 1。然后我们就可以知道:4 = 1 << 2 = UIViewAutoresizingFlexibleRightMargin;1 = 1 << 0 = UIViewAutoresizingFlexibleLeftMargin。所以上面的代码就被解释成:

[subView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin];  // 子视图距离父视图左右间距不变,宽度随父视图宽度的缩放而缩放。

不难发现,这样以位移的方式指定autoresizingMask枚举值,也契合了storyboard中可以给子控件设置多个方向的约束的情景。如下图:

image

注意:Autoresizing只能设置父子视图之间的关系,也就是说,Autoresizing只能控制子视图和父视图之间的位置/大小关系。Autoresizing不能设置兄弟视图之间的关系,当然也不能设置完全不相关的两个视图之间的关系。正因为Autoresizing只能设置父子视图之间的关系,所以,Autoresizing只能应用于两个视图之间,不能应用于三个或者更多视图之间。毕竟,一个儿子不可能有两个亲爹。
注意:UIView的autoresizesSubviews属性为YES时(默认为YES),autoresizingMask才会生效。也就是说,当我们想要利用autoresizingMask指定某个控件和其父控件的关系时候,必须autoresizesSubviews = YES。
注意:值得注意的是,autoresizingMask的每个枚举值都带有Flexible这个单词,其意思是:灵活的,弹性的。所以,我们在对其枚举值进行一一翻译。

      UIViewAutoresizingNone // 就是不自动调整。
  UIViewAutoresizingFlexibleLeftMargin // 自动弹性的调整与superView左边的距离,保证与superView右边的距离不变。
  UIViewAutoresizingFlexibleRightMargin // 自动弹性的调整与superView的右边距离,保证与superView左边的距离不变。
  UIViewAutoresizingFlexibleTopMargin // 自动弹性d调整与superView顶部的距离,保证与superView底部的距离不变。
  UIViewAutoresizingFlexibleBottomMargin // 自动弹性的调整与superView底部的距离,也就是说,与superView顶部的距离不变。
  UIViewAutoresizingFlexibleWidth // 自动弹性的调整自己的宽度,保证与superView左边和右边的距离不变。
  UIViewAutoresizingFlexibleHeight // 自动弹性的调整自己的高度,保证与superView顶部和底部的距离不变。

看完翻译才恍然大悟,原来这些枚举值和storyboard中的虚线是相反的,当我们点击了storyboard中国的某个虚线后代表其间距被固定,而我们用代码设置则代表相反方向的间距被固定。
但是,例外的是,storyBoard中子控件内部的两个带箭头的虚线和枚举值UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight具有相同的意义。也就是说,当我们点击了storyBoard中子控件内带箭头的水平虚线使之变为实线时,就相当于[subView setAutoresizingMask:UIViewAutoresizingFlexibleWidth];

image

当我们点击了storyBoard中子控件内带箭头的垂直虚线使之变为实线时,就相当于[subView setAutoresizingMask UIViewAutoresizingFlexibleHeight];

image

注意:简而言之,4条margin虚线代表设置autoresizingMask中的与之对应的4枚举值,而实线的width和height才代表设置autoreMask中与之对应的2个枚举值。

1.2.3.Autoresizing的组合场景

autoresizingMask枚举值及其对应的storyBoard预览效果说明

UIViewAutoresizingMaskNone
view的frame不会随superview的改变而改变,相当于frame(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)

image

UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin
view和其superView左间距和上间距固定,宽高固定,右间距和底部间距随父控件的缩放而按比例缩放

image

UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin
view与其superView上间距固定,右间距固定,宽高固定,左间距、下间距锁父控件的缩放而缩放

image

UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin
view与其superView的右间距、底部间距固定,宽高固定,上间距、左间距随父控件的缩放而缩放

image

UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin
view与其superView的左间距、底部间距固定,宽高固定,右间距、上间距随父控件的缩放而缩放

image

UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight

view与其superView的上间距、左间距、底部间距固定,宽度固定。高度、右边距随父控件缩放而缩放

image

UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth
view与其superView的左间距、上间距、右间距固定,高度固定。宽度、底部间距随父控件的缩放而缩放

image

UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight
view与其superView的上间距、右间距、底部间距固定,宽度固定。高度、左间距随父控件的缩放而缩放

image

UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth
view与其superView的左间距、右间距、底部间距固定,高度固定。宽度、上间距随父控件的缩放而缩放

image

UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view与其superView的左间距、上间距、底部间距固定。宽度、高度、右间距随父控件的缩放而缩放

image

UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view与其superView的左间距、上间距、右间距固定。宽度、高度、底部间距随父控件的缩放而缩放

image

UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view与其superView的上间距、右间距、左间距固定。宽度、高度、左间距随父控件的缩放而缩放

image

UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view与其superView的左间距、底部间距、右间距固定。宽度、高度、上间距随父控件的缩放而缩放

image

UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottom
view与其superView的宽高比例维持不变,上下左右间距也随其superView的缩放而缩放

image

UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin
view与其superView的左右间距固定,高度固定,宽度、上间距、底部间距随其父控件的缩放而缩放

image

UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin
view与其superView的上下左右边距的比例维持不变,宽高固定,反映在storyBoard中,就是什么都不设置

image

UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin
左边距、右边距、宽按比例调整,上边距固定,下边距固定,高度固定(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)垂直方向是同样效果,故不列举

image

UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
自动调整view的宽和高,保证上下左右边距不变。如把tableView设置为此属性,那么无论viewController的view是多大,都能自动铺满

image

不合理布局

UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin
view与其superView的左边距和右边距的比例维持不变,上下间距固定,宽高固定(下图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)这种约束方式相当于上下间距固定,宽高固定,那么父控件高度缩放的时候就会产生冲突,所以这种布局方式是不合理的

image
image

UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin
view与其superView的上边距和下边距的比例维持不变,左右间距固定,宽高固定(这种约束方式相当于左右间距固定,宽高固定,那么父控件宽度缩放的时候就会产生冲突,所以这种布局方式也是不合理的)

image
image

UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth
view与其superView的左边距和width按比例调整,高度固定,右边距固定,上边距固定,下边距固定(下图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)(这种约束方式相当于上下间距固定,高度固定,那么父控件高度缩放的时候就会产生冲突,所以这种布局方式也是不合理的)

image

综上发现,只要是我们在水平方向同时固定了左边距和右边距,那么我们千万不能固定子控件的宽度(反应在storyBoard中的设置,也就是必须使控制子控件宽度的虚线变为实线)。同理, 如果垂直方向同时固定了上边距和下边距,那么我们不能固定子控件的高度(反应在storyBoard中的设置,也就是必须使控制子控件高度的虚线变为实线)。

控制器的view的autoresizing

注意:如果我们在storyBoard中选中控制器的view,然后在尺寸检查器中查看会发现,autoresizing中控制子控件的宽度和高度的虚线自动变成了实线(然而我并没有点击),这是因为控制器的view的宽高是一个默认值,默认和屏幕的尺寸相等,所以我们不能通过autoresizing来设置控制器的宽高。从另一个角度也能解释:autoresizing是约束子控件和父控件之间的位置关系的,控制器的view并没有父控件,所以不能通过autoresizing来约束控制器的view。

链接:https://www.jianshu.com/p/b637d3d21606

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339