自动布局虽然在iOS6的时候已经推出,不过由于各个原因并没有被开发组广泛使用。一方面是大家的app支持版本都是低于iOS6的,另一方面来说是Xcode支持木有现在这么好。以前由于iPhone设备相对固定,所以在纯代码,纯坐标的布局下很流行,不过现在随着iPhone6发布,如果还要写一大堆乱七八糟的绝对坐标去适配,那工作量和维护成本是很大的。

下面的一些基础直接拿小伙伴分享整理的吧,之后向大家推荐一个开源的库,对AutoLayout进行了封装,用起来很简单也高效。

1.AutoLayout是什么?

使用一句Apple的官方定义的话

 
  AutoLayout是一种基于约束的,描述性的布局系统。
  Auto Layout Is a Constraint-Based, Descriptive Layout System.
 
关键词:

  • 基于约束 - 和以往定义frame的位置和尺寸不同,AutoLayout的位置确定是以所谓相对位置的约束来定义的,比如x坐标为superView的中心,y坐标为屏幕底部上方10像素
  • 描述性 - 约束的定义和各个view的关系使用接近自然语言或者可视化语言(VFL)的方法来进行描述
  • 布局系统 - 即字面意思,用来负责界面的各个元素的位置。

总而言之,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.

1.1AutoLayout和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不具备的优良特性,以帮助我们更方便地构建界面
 
 
2.基本原理
假设有一个按钮,你想把它放置在屏幕的中央。视图中心和按钮中心的相对位置可以简
单地定义成如下:

·按钮的 center.x 相当于视图中心的 center.x

 
·按钮的 center.y 相当于视图中心的 center.y
苹果发现很多的 UI 组件的位置可以使用一个简单的方程等式得到解决:
 
item1.attribute = multiplier ⨉ item2.attribute + constant

例如:使用这个方程式,我们可以很容易地将一个按钮放置到他的父视图中,如下所 示:

    Button.center.x=(button.superview.center.x*1)+0
Button.center.y=(button.superview.center.y*1)+0

即:y = m*x + b
3.相关知识
3.1 使用线性公式添加描述
iOS6 引入类来描述约束条件:
NSLayoutConstraint NS_CLASS_AVAILABLE_IOS(6_0)
方法:constraintWithItem
[NSLayoutConstraint constraintWithItem:(id)
attribute:(NSLayoutAttribute)
relatedBy:(NSLayoutRelation)
toItem:(id)
attribute:(NSLayoutAttribute)
multiplier:(CGFloat)
constant:(CGFloat)];

(item1.attribute = multiplier ⨉ item2.attribute + constant)
NSLayoutAttribute:
typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
    NSLayoutAttributeLeft = 1,                     //左侧
    NSLayoutAttributeRight,                        //右侧
    NSLayoutAttributeTop,                          //上方
    NSLayoutAttributeBottom,                       //下方
    NSLayoutAttributeLeading,                      //首部
    NSLayoutAttributeTrailing,                     //尾部
    NSLayoutAttributeWidth,                        //宽度
    NSLayoutAttributeHeight,                       //高度
    NSLayoutAttributeCenterX,                      //X轴中心
    NSLayoutAttributeCenterY,                      //Y轴中心
    NSLayoutAttributeBaseline,                     //文本底标线
                                                                                                                                                    
    NSLayoutAttributeNotAnAttribute = 0            //没有属性
};
 
NSLayoutAttributeLeading/NSLayoutAttributeTrailing的区别是left/right永远是指左右,
leading/trailing在某些从右至左习惯的地区(希伯来语等)会变成,leading是右边,trailing是左边
 
NSLayoutRelation:
 
typedef NS_ENUM(NSInteger, NSLayoutRelation) {
    NSLayoutRelationLessThanOrEqual = -1,          //小于等于
    NSLayoutRelationEqual = 0,                     //等于
    NSLayoutRelationGreaterThanOrEqual = 1,        //大于等于
};
 
 
 
需求:button始终处于屏幕中心位置
<demo MainVC>  
 
 
@interface UIView (UIConstraintBasedLayoutInstallingConstraints)

- (NSArray *)constraints NS_AVAILABLE_IOS(6_0);

- (void)addConstraint:(NSLayoutConstraint *)constraint NS_AVAILABLE_IOS(6_0);
- (void)addConstraints:(NSArray *)constraints NS_AVAILABLE_IOS(6_0);
- (void)removeConstraint:(NSLayoutConstraint *)constraint NS_AVAILABLE_IOS(6_0);
- (void)removeConstraints:(NSArray *)constraints NS_AVAILABLE_IOS(6_0);
@end

 
 
 
在添加时需要注意的是添加的目标view要遵循以下规则:
 
1.对于两个同层级view之间的约束关系,添加到他们的父view上
 
2.对于两个不同层级view之间的约束关系,添加到他们最近的共同父view上
 
3.对于有层次关系的两个view之间的约束关系,添加到层次较高的父view
 
简单来说,找父类。
 
 
 
<Demo,ButtonVC> 两个button
 
 
 
 
3.2     使用 Visual Format Language 定义水平和垂直约束
 
Visual Format Language 可视格式语言,用来描述约束条件,这种语言是对视觉描述的一种抽象,大概过程看起来是这样的:
 
比如两个按钮的间距
 
 
 
cancel 与 accept之间水平标准间距 :[cancelButton]-[acceptButton]
 
 
官方文档:

Visual Format Syntax

The following are examples of constraints you can specify using the visual format. Note how the text visually matches the image.

Standard Space

[button]-[textField]

Width Constraint

[button(>=50)]

Connection to Superview

|-50-[purpleBox]-50-|

Vertical Layout

V:[topField]-10-[bottomField]

Flush Views

[maroonView][blueView]

Priority

[button(100@20)]

Equal Widths

[button1(==button2)]

Multiple Predicates

[flexibleButton(>=70,<=100)]

A Complete Line of Layout

|-[find]-[findNext]-[findField(>=20)]-|

 
 
 
 
例:
 
如图所示VFL:
email:
H:|-[_textFieldEmail]-|
V:|-100-[_textFieldEmail]
 
confirm email:
H:|-[_textFieldConfirmEmail]-|
V:[_textFieldEmail]-[_textFieldConfirmEmail]
 
register button:
V:[_textFieldConfirmEmail]-[_registerButton]
 
 
 
缺陷:
1.不能表达是一个固定的长宽比,如:imageView.width = 2 * imageView.height
2.UI 组件在 水平方向的居中条件不能由 Visual Format Language 定义
3. ...
 
 
 
方法:
visualFormat:     VFL 可视格式语言
 
 
 
NSLayoutFormatOptions:
 
typedef NS_OPTIONS(NSUInteger, NSLayoutFormatOptions) {
    NSLayoutFormatAlignAllLeft = (1 << NSLayoutAttributeLeft),
    NSLayoutFormatAlignAllRight = (1 << NSLayoutAttributeRight),
    NSLayoutFormatAlignAllTop = (1 << NSLayoutAttributeTop),
    NSLayoutFormatAlignAllBottom = (1 << NSLayoutAttributeBottom),
    NSLayoutFormatAlignAllLeading = (1 << NSLayoutAttributeLeading),
    NSLayoutFormatAlignAllTrailing = (1 << NSLayoutAttributeTrailing),
    NSLayoutFormatAlignAllCenterX = (1 << NSLayoutAttributeCenterX),
    NSLayoutFormatAlignAllCenterY = (1 << NSLayoutAttributeCenterY),
    NSLayoutFormatAlignAllBaseline = (1 << NSLayoutAttributeBaseline),
   
    NSLayoutFormatAlignmentMask = 0xFFFF,
   
    /* choose only one of these three
     */
    NSLayoutFormatDirectionLeadingToTrailing = 0 << 16, // default
    NSLayoutFormatDirectionLeftToRight = 1 << 16,
    NSLayoutFormatDirectionRightToLeft = 2 << 16, 
   
    NSLayoutFormatDirectionMask = 0x3 << 16, 
};
 
 
 
注:
在vertical方向 为 left,right,leading,trailing,centerX
在horizontal方向为 top,bottom,centerY,baseLine (baseLine即为文本底部对齐) 
 
 
 
metrics:
[constraints addObjectsFromArray:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:|-padding-[messageTextView]-kTopAndBottomPadding-|"
options:NSLayoutFormatAlignAllTop
metrics:@{@"padding":@5.0}
views:variableBindings]];
 
views:
A dictionary of views that appear in the visual format string. The keys must be the string values used in the visual format string, and the values must be the view objects.
 
example 1:
V:[_textFieldEmail]-[_textFieldConfirmEmail]
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_textFieldConfirmEmail, _textFieldEmail);
 
example 2:
H:|-[_textFieldEmail]-|
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_textFieldEmail);
 
方法原型:
 
/* This macro is a helper for making view dictionaries for +constraintsWithVisualFormat:options:metrics:views:. 
 NSDictionaryOfVariableBindings(v1, v2, v3) is equivalent to [NSDictionary dictionaryWithObjectsAndKeys:v1, @"v1", v2, @"v2", v3, @"v3", nil];
 */
#define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)
UIKIT_EXTERN NSDictionary *_NSDictionaryOfVariableBindings(NSString *commaSeparatedKeysString, id firstValue, ...) NS_AVAILABLE_IOS(6_0); // not for direct use
 
 
<Demo FirstVC> 两个textfiled,一个按钮
 
<Demo ThirdVC>参数:NSLayoutFormatOptions:
 
<Demo ButtonVC> 两种方法比较
 
<Demo SecondVC>使用不同父类的 view 进行约束
 
 
3.3 NSLayoutConstraint 
(过一遍)
 
 
4.XIB 使用 layout
4.1 使用方法
4.2 问题修复
 
 
5.
容易出现的错误

 
因为涉及约束问题,因此约束模型下的所有可能出现的问题这里都会出现,具体来说包括两种:
 
*)  Ambiguous Layout 布局不能确定
*)  Unsatisfiable Constraints 无法满足约束
 
布局不能确定指的是给出的约束条件无法唯一确定一种布局,也即约束条件不足,无法得到唯一的布局结果。这种情况一般添加一些必要的约束或者调整优先级可以解决。无法满足约束的问题来源是有约束条件互相冲突,因此无法同时满足,需要删掉一些约束。两种错误在出现时均会导致布局的不稳定和错误,Ambiguous可以被容忍并且选择一种可行布局呈现在UI上,Unsatisfiable的话会无法得到UI布局并报错。

UIView+AutoLayout (GitHub地址:https://github.com/smileyborg/UIView-AutoLayout)

这个第三方写的类别,将需要代码创建的视图的约束进行了一层封装。如果用代码设置约束的话,用可视化语言,代码量少,如果团队成员都很熟悉的情况下,可读性还行!用另一种方法创建一个个约束,然后加上view上去,虽然可读性强,但是代码量大.而这个类别就是将那些方法进行一层可读性更强的方法,和自动布局的本意一样,只要你调用简单方法去描述各个view之间的关系,而创建的约束的方法,我们不需要在去关心。作者也增加了一个数组的类别,是为了方便多个view一起创建约束使用。具体的可以直接去GitHub上下载,然后查看示例的demo。

iOS自动布局学习(UIView+AutoLayout)的更多相关文章

  1. iOS学习——UIView的研究

    在iOS开发中,我们知道有一个共同的基类——NSObject,但是对于界面视图而言,UIView是非常重要的一个类,UIView是很多视图控件的基类,因此,对于UIView的学习闲的非常有必要.在iO ...

  2. 【转】iOS学习之Autolayout(代码添加约束) -- 不错不错

    原文网址:http://www.cnblogs.com/HypeCheng/articles/4192154.html DECEMBER 07, 2013 学习资料 文章 Beginning Auto ...

  3. iOS学习之Autolayout

    转载自:http://vit0.com/blog/2013/12/07/iosxue-xi-zhi-autolayout/ 学习资料 文章 Beginning Auto Layout Tutorial ...

  4. iOS学习笔记——AutoLayout的约束

    iOS学习笔记——AutoLayout约束 之前在开发iOS app时一直以为苹果的布局是绝对布局,在IB中拖拉控件运行或者直接使用代码去调整控件都会发上一些不尽人意的结果,后来发现iOS在引入了Au ...

  5. iOS自动布局进阶用法

    本文主要介绍几个我遇到并总结的相对高级的用法(当然啦牛人会觉得这也不算什么). 简单的storyboard中上下左右约束,固定宽高啥的用法在这里就不做赘述了. autolayout自动布局是iOS6以 ...

  6. 【转】iOS自动布局进阶用法

    原文网址:http://www.cnblogs.com/dsxniubility/p/4266581.html 本文主要介绍几个我遇到并总结的相对高级的用法(当然啦牛人会觉得这也不算什么). 简单的s ...

  7. iOS自动布局——Masonry详解

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由鹅厂新鲜事儿发表于云+社区专栏 作者:oceanlong | 腾讯 移动客户端开发工程师 前言 UI布局是整个前端体系里不可或缺的一环 ...

  8. iOS自动布局高级用法 && 纯代码约束写法

    本文主要介绍几个我遇到的总结的高级用法(当然我相信肯定有不少比这还高级的). 简单的storyboard中上下左右约束,固定宽高啥的用法在这里就不做赘述了. autolayout自动布局是iOS6以后 ...

  9. IOS基础学习-2: UIButton

    IOS基础学习-2: UIButton   UIButton是一个标准的UIControl控件,UIKit提供了一组控件:UISwitch开关.UIButton按钮.UISegmentedContro ...

随机推荐

  1. PLSQL流函数代码 540页 【我】

    540页 流函数代码 -- Create table create table STOCKTABLE ( TICKER ), TRADE_DATE DATE, OPEN_PRICE NUMBER, C ...

  2. vue-cli4.0 基于 antd-design-vue 二次封装发布到 npm 仓库

    1. 安装 cli npm install -g @vue/cli vue create winyh-ui 2.安装 antd-design-vue cnpm i ant-design-vue --s ...

  3. [ kvm ] 学习笔记 9:WebVirtMgr 基础及安装使用

    目录- 1. 前言- 2. webvirtmgr 简介- 3. webvirtmgr 部署实践    - 3.1 配置 webvirtmgr 主机    - 3.2 kvm node节点配置    - ...

  4. 【serviceaccount 和 clusterrolebinding】

    kubectl get clusterrolebinding kubectl create clusterrolebinding suosheng-rebinding --clusterrole=cl ...

  5. Java基础教程:内部类

    Java基础教程:内部类 内部类 内部类,是指在一个类的内部定义的类.就像下面这样: public class EnclosingClass {   . . .   public class Nest ...

  6. 【GStreamer开发】GStreamer基础教程16——平台相关的element

    目标 虽然GStreamer是跨平台的framework,但不是所有的element都是在所有平台下都有的.比如,音频和视频的sink都非常依赖于当前的window系统,根据当前的平台需要选择不同的e ...

  7. ztree节点名称排序

    // result 为后台返回的集合,在渲染tree前的数据 result = result.sort(function (a, b) { // 判断前面一个是字母,后面一个不是字母,那么不换位置,返 ...

  8. CSS float属性

    表示向左浮动,比如多个div在一个页面上,默认情况是:一行一个div,但是只要在div的css中使用float:left,可以使一行有多个div,这样可以把网页划分成很多块,但是使用该属性会影响后面的 ...

  9. 【剑指offer】面试题 42. 连续子数组的最大和

    面试题 42. 连续子数组的最大和 NowCoder 题目描述 输入一个整型数组,数组里有正数也有负数.数组中一个或连续的多个整数组成一个子数组.求所有子数组的和的最大值. 示例: 输入: [-2,1 ...

  10. 《Mysql - Mysql 是如何保证主备一致的?》

    一:Mysql 主备的基本原理? - 主备切换流程(M-S 架构) -  - 在状态 1 中,客户端的读写都直接访问节点 A,而节点 B 是 A 的备库,只是将 A 的更新都同步过来,到本地执行. - ...