iOS自动布局学习(UIView+AutoLayout)

  自动布局虽然在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([email protected])]

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。

时间: 2024-08-02 15:12:03

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

iOS 自动布局

自动布局框架 Masonry PureLayout FLKAutoLayout KeepLayout UIView+Autolayout 相关教程: iOS 开发实践之 Auto Layout Masonry介绍与使用实践(快速上手Autolayout) IOS自动布局之Autoresizing iOS中的相对布局:AutoLayout

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

原文网址:http://www.cnblogs.com/dsxniubility/p/4266581.html 本文主要介绍几个我遇到并总结的相对高级的用法(当然啦牛人会觉得这也不算什么). 简单的storyboard中上下左右约束,固定宽高啥的用法在这里就不做赘述了. autolayout自动布局是iOS6以后出现的,但是在开始的一段时间里大家并不怎么会用,都是一上来先勾掉.之后随着5s,iPhone6的出现屏幕多种多样.用多层if来判断尺寸已经完全hold不住了才开始学习自动布局. 在这之前

iOS自动布局高级用法及纯手码约束写法

本文主要介绍几个我遇到的总结的高级用法(当然我相信肯定有不少比这还高级的). 简单的storyboard中上下左右约束,固定宽高啥的用法在这里就不做赘述了. autolayout自动布局是iOS6以后出现的,但是在开始的一段时间里大家并不怎么会用,都是一上来先勾掉.之后随着5s,iPhone6的出现屏幕多种多样.用多层if来判断尺寸已经完全hold不住了才开始学习自动布局. 在这之前有个叫自动伸缩的autoresizing属性,这个主要用于一个控件和自己父控件之间的关系.只有autolayout

iOS自动布局——Masonry详解

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由鹅厂新鲜事儿发表于云+社区专栏 作者:oceanlong | 腾讯 移动客户端开发工程师 前言 UI布局是整个前端体系里不可或缺的一环.代码的布局是设计语言与用户视觉感受沟通的桥梁,不论它看起来多么简单或是琐碎,但不得不承认,绝大部分软件开发的问题,都是界面问题.那么,如何高效的完成UI开发,也是软件行业一直在克服的问题. 所以,软件界面开发的核心点即是:如何减少UI设计稿的建模难度和减少建模转化到代码的实现难度 最初iOS提供了

iOS: How To Make AutoLayout Work On A ScrollView

iOS: How To Make AutoLayout Work On A ScrollView Posted on June 11th, 2014 Ok, I’ll admit. I’ve been seriously struggling with AutoLayout ever since it’s been introduced. I understand the concept, and I LOVE the idea of it, but when I actually do it,

iOS 动画学习

图层树.寄宿图以及图层几何学(一)图层的树状结构 技术交流新QQ群:414971585 巨妖有图层,洋葱也有图层,你有吗?我们都有图层 -- 史莱克 Core Animation其实是一个令人误解的命名.你可能认为它只是用来做动画的,但实际上它是从一个叫做Layer Kit这么一个不怎么和动画有关的名字演变而来,所以做动画这只是Core Animation特性的冰山一角. Core Animation是一个复合引擎,它的职责就是尽可能快地组合屏幕上不同的可视内容,这个内容是被分解成独立的图层,存

开源中国iOS客户端学习

开源中国iOS客户端学习 续写前言 <开源中国iOS客户端学习>续写前系列博客    http://blog.csdn.net/column/details/xfzl-kykhd.html 开源中国iOS客户端学习——序 说到这款开源软件就得提到她的娘家了--开源中国社区: 开源中国社区简介:开源中国 www.oschina.net 成立于2008年8月,是目前中国最大的开源技术社区.传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现.使用.并交流开源技术的平台.目前开源中国社区已收

ios开发学习路径

1.第一点要求 ,能比较顺畅的阅读官方的文档 如果你连官方的文档读起来都非常困难,那你还谈什么提高和进阶,咱们学习iOS的所有权威的资料都来自apple开发者网站,靠逛论坛看看帖子不是出路. 如果这点没达到,那就从阅读官方文档开始吧,找一篇你比较熟悉的技术的官方文档,比如:View Programming Guide for iOS  自己阅读,翻译,里面不懂的单词,记下来,多学几遍,这些你不懂的单词,在以后你看其他时文档里还会出现无数次的.坚持几个月后,你会发现,英文的文档,看起来比中文的顺眼

ios网络学习------6 json格式数据的请求处理

#import "MainViewController.h" #import "Video.h" #define kBaseURL @"http://192.168.3.252/~apple" @interface MainViewController ()<UITableViewDataSource, UITableViewDelegate> @property (strong, nonatomic) NSArray *dataLi