NSLayoutConstraint

继承自:NSObject
**Available in iOS 6.0 and later **

constraint定义了一种位置关系,通过约束来将两个UI对象的位置确定在屏幕上。每个约束遵循如下的这个线性公式:

item1.attribute1 = multiplier × item2.attribute2 + constant

在这个等式中,attribute1和attribute2是两个自动布局的变量,就是通过它们来适配不同的屏幕尺寸。其他的值在你创建约束的时候就该定下来了。举例来说,如果你要定义两个按钮之间的相对位置,你可能会说:“第二个按钮的最左边要距离第一个按钮的最右边有8个point的距离。”这个约束关系的线性公式就如下所示:

// positive values move to the right in left-to-right languages like English.
button2.leading = 1.0 × button1.trailing + 8.0

随后自动布局就会自动调整两个按钮左右边缘的位置,直到上述等式左右相等。这里值得注意的是,自动布局并不是单方面地调整一个按钮来满足条件,而是在需要的时候调整其中的任意一个,甚至两个按钮的位置都调整。

等式相等意味着,你可以改变item的顺序,也就是说你可以对这个等式做随意的一次方程计算。经过改变,等式可以更好地表达两个item之间的约束关系。提醒一句,改变等式别忘了随之改变multiplier(系数)和constant(常数)。举个例子,下面的两个等式就表达相同的约束:

// These equations produce identical constraints
button2.leading = 1.0 × button1.trailing + 8.0
button1.trailing = 1.0 × button2.leading - 8.0

一个有效的布局方案会有一套完整的约束,这意味着由许多等式组成,这些等式有且仅有唯一一个解来定位一个item。要看怎么来定义一个有效布局,请移步 Auto Layout Guide中的Resolving Auto Layout Issues

另外,约束也不只有两者相等这一种,还可以用大于等于(>=),或者小于等于(<=)来描述约束关系。约束还有优先级,范围是1~1000,1000代表必须实现(required),此外都是根据优先级可选择实现(optional)。默认优先级都是1000。

自动布局实现了所有必须实现的约束之后,会根据优先级顺序来尝试去实现可选约束。如果实现不了,就尽可能接近要求,然后继续处理下个可选约束。

通过这套等式、不等式、优先级的组合,你完全可以定义一套极具灵活性的布局,来让你的UI元素自适应任何变化。


创建约束

+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format
                                                                options:(NSLayoutFormatOptions)opts
                                                                metrics:(NSDictionary<NSString *,
                                                                                 id> *)metrics
                                                                  views:(NSDictionary<NSString *,
                                                                                 id> *)views

根据Visual Format Language以及对齐选择项来创建一组对象的约束

+ (instancetype)constraintWithItem:(id)view1
                         attribute:(NSLayoutAttribute)attr1
                         relatedBy:(NSLayoutRelation)relation
                            toItem:(id)view2
                         attribute:(NSLayoutAttribute)attr2
                        multiplier:(CGFloat)multiplier
                          constant:(CGFloat)c

最常用的约束方法,根据两个item的指定attribute来约束item的位置,返回一个NSLayoutConstraint对象。iOS6.0

参数 含义
view1 第一个item
attr1 item1的参考属性
relation 两个item参考属性之间的关系,详见NSLayoutRelation
view2 item1的参照物,item2
multiplier item2的参考属性带入计算时需要缩放的倍数
c item2的属性乘以倍数之后加上这个常量,来得到约束的最终结果

论述:也可能出现这样的情况,item1的这个约束并不需要参照物item2(比如说约束宽度),这时候在item2上代入nil,attr2代入NSLayoutAttributeNotAnAttribute


激活或关闭约束

@property(getter=isActive) BOOL active //iOS8.0

这个属性可以激活或者关闭一个约束,只有激活状态的约束才能影响最终的布局。需要注意的是,如果两个items的不在同一个界面上,则计算结果会报错。新创建的约束对象的状态默认为关闭。

你可以在两个items所在的view上调用addConstraint:或者removeConstraint:来激活或者关闭一个约束。但更方便的是直接改变这个属性来替代调用这两个方法。

+ (void)activateConstraints:(NSArray<NSLayoutConstraint *> *)constraints //iOS8.0
+ (void)deactivateConstraints:(NSArray<NSLayoutConstraint *> *)constraints //iOS8.0

这两个方法可以一次性激活/关闭一堆约束的激活状态。通常来讲,用这两个方法比一个个修改约束的active属性在性能上更具优势。


约束内部数据的接口

@property UILayoutPriority priority //(iOS6.0)

这里再提一遍,约束并不是非真即假的,而且如果一个约束并不是必须实现的,那么自动布局也只会去尽可能贴近等式、不等式的计算结果。

一个约束被添加并激活了之后,它的优先级就不能在必须实现和可选实现中来回修改了。但是如果同是可选实现的话,还是能够在约束激活后即时修改优先级的具体数值。

@property(readonly, assign) id firstItem //iOS6.0
@property(readonly) NSLayoutAttribute firstAttribute //iOS6.0
@property(readonly) NSLayoutRelation relation //iOS6.0
@property(readonly, assign) id secondItem //iOS6.0
@property(readonly) NSLayoutAttribute secondAttribute //iOS6.0
@property(readonly) CGFloat multiplier //iOS6.0

上略

@property CGFloat constant //iOS6.0

和其他属性不同,constant在约束创建之后仍可以修改。在现有的约束上修改constant要比移除一个约束,再新建一个除了constant外没啥区别的约束要效率得多。


标识一个约束

@property(copy) NSString *identifier //iOS7.0

约束的标识从description中就能得到


Controlling Constraint Archiving

@property BOOL shouldBeArchived //iOS6.0

When a view is archived, it archives some but not all constraints in its constraints
array. The value ofshouldBeArchived
informs the view if a particular constraint should be archived by the view.
If a constraint is created at runtime in response to the state of the object, it isn't appropriate to archive the constraint. Instead you archive the state that gives rise to the constraint. The default value for this property is NO


枚举常量

enum { 
NSLayoutRelationLessThanOrEqual = -1, 
NSLayoutRelationEqual = 0, 
NSLayoutRelationGreaterThanOrEqual = 1,
};
typedef NSInteger NSLayoutRelation; //iOS6.0
  • NSLayoutRelationLessThanOrEqual
    前一个属性小于等于后一个属性
  • NSLayoutRelationEqual
    两个属性完全相等
  • NSLayoutRelationGreaterThanOrEqual
    前一个属性大于等于后一个属性
typedef enum: NSInteger { 
NSLayoutAttributeLeft = 1, 
NSLayoutAttributeRight, 
NSLayoutAttributeTop, 
NSLayoutAttributeBottom, 
NSLayoutAttributeLeading, 
NSLayoutAttributeTrailing, 
NSLayoutAttributeWidth, 
NSLayoutAttributeHeight, 
NSLayoutAttributeCenterX, 
NSLayoutAttributeCenterY, 
NSLayoutAttributeBaseline, 
NSLayoutAttributeLastBaseline = NSLayoutAttributeBaseline, 
NSLayoutAttributeFirstBaseline, 

NSLayoutAttributeLeftMargin, 
NSLayoutAttributeRightMargin, 
NSLayoutAttributeTopMargin, 
NSLayoutAttributeBottomMargin, 
NSLayoutAttributeLeadingMargin, 
NSLayoutAttributeTrailingMargin, 
NSLayoutAttributeCenterXWithinMargins, 
NSLayoutAttributeCenterYWithinMargins,
 
NSLayoutAttributeNotAnAttribute = 0
} NSLayoutAttribute; //iOS6.0 iOS8.0
  • NSLayoutAttributeLeading
    在习惯由左向右看的地区,相当于NSLayoutAttributeLeft。在习惯从右至左看的地区,相当于NSLayoutAttributeRight
  • NSLayoutAttributeTrailing
    在习惯由左向右看的地区,相当于NSLayoutAttributeRight。在习惯从右至左看的地区,相当于NSLayoutAttributeLeft
  • magin
    一系列边界约束属性如下图所示:


    36R3qqu.png
  • NSLayoutAttributeNotAnAttribute
    约束用不着第二个item的时候,第二个属性处选填
enum { 
/* choose only one of these */ 
NSLayoutFormatAlignAllLeft = NSLayoutAttributeLeft, 
NSLayoutFormatAlignAllRight = NSLayoutAttributeRight, 
NSLayoutFormatAlignAllTop = NSLayoutAttributeTop, 
NSLayoutFormatAlignAllBottom = NSLayoutAttributeBottom, 
NSLayoutFormatAlignAllLeading = NSLayoutAttributeLeading, 
NSLayoutFormatAlignAllTrailing = NSLayoutAttributeTrailing, 
NSLayoutFormatAlignAllCenterX = NSLayoutAttributeCenterX, 
NSLayoutFormatAlignAllCenterY = NSLayoutAttributeCenterY, 
NSLayoutFormatAlignAllBaseline = NSLayoutAttributeBaseline, 

NSLayoutFormatAlignmentMask = 0xFF, 

/* choose only one of these three */ 
NSLayoutFormatDirectionLeadingToTrailing = 0 << 8, // default  
NSLayoutFormatDirectionLeftToRight = 1 << 8, 
NSLayoutFormatDirectionRightToLeft = 2 << 8, 

NSLayoutFormatDirectionMask = 0x3 << 8,
};
typedef NSUInteger NSLayoutFormatOptions;

对齐选择项,字面意思不累述

enum { 
UILayoutPriorityRequired = 1000, 
UILayoutPriorityDefaultHigh = 750, 
UILayoutPriorityDefaultLow = 250, 
UILayoutPriorityFittingSizeLevel = 50,
};typedef float UILayoutPriority;

iOS7.1后不使用,直接根据需要设定约束的priority属性值即可。

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

推荐阅读更多精彩内容