自动布局虽然在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. ios开发注意事项小总结

    一.LaunchScreen LaunchScreen产生原因:代替之前的启动图片 好处: 1.可以展示更多的东西 2.可以只需要出一个尺寸的图片. 启动图片的优先级 启动图片 < Launch ...

  2. window下安装docker

    下载docker toolbox https://mirrors.aliyun.com/docker-toolbox/windows/docker-toolbox/ 1,.双击安装DockerTool ...

  3. LeetCode_205. Isomorphic Strings

    205. Isomorphic Strings Easy Given two strings s and t, determine if they are isomorphic. Two string ...

  4. Delphi中进行延时的4种方法

     1.挂起,不占CPUsleep2.不挂起,占cpuprocedure Delay(msecs:integer);varFirstTickCount:longint;beginFirstTickCou ...

  5. mongodb多个条件查询in,日期查询,嵌套查询,统计集合总数等常用实例

    1. 多个条件查询in in db.inventory.find( { qty: { $in: [ 5, 15 ] } } ) 2. 日期查询 db.books.find({}) 查询时间大于6-,结 ...

  6. PBU流速权

    PBU概念 PBU是“Participant Business Unit”的英文缩写,中文全称是“参与者交易业务单元”. 在新版交易规则中对此有定义:“参与者交易业务单元”是指交易参与人据此参与本所证 ...

  7. 将MySQL一张表的数据迁移到MongoDB数据库的Java代码示例

    Java代码: package com.zifeiy.snowflake.handle.etl.mongodb; import java.sql.Connection; import java.sql ...

  8. 【Leetcode_easy】840. Magic Squares In Grid

    problem 840. Magic Squares In Grid solution: class Solution { public: int numMagicSquaresInside(vect ...

  9. 常见浏览器CSS hack方法总结

    ie6和ie7 #tip {*background:black; /*IE7 背景变黑色*/_background:orange; /*IE6 背景变橘色*/} IE8和IE9 :root .test ...

  10. 一个unsigned int 数的二进制表示中有多少个1

    这是一道面试题可以用以下的一些方案.第一种是很容易想到的采用循环的方式并且与1进行位与运算,具体代码如下.  1unsigned int GetBitNumOfOne_ByLoop1(unsigned ...