繼承自:NSObject
**Available in iOS 6.0 and later **
constraint定義了一種位置關系锹雏,通過約束來將兩個UI對象的位置確定在屏幕上。每個約束遵循如下的這個線性公式:
item1.attribute1 = multiplier × item2.attribute2 + constant
在這個等式中术奖,attribute1和attribute2是兩個自動布局的變量礁遵,就是通過它們來適配不同的屏幕尺寸。其他的值在你創(chuàng)建約束的時候就該定下來了采记。舉例來說佣耐,如果你要定義兩個按鈕之間的相對位置,你可能會說:“第二個按鈕的最左邊要距離第一個按鈕的最右邊有8個point的距離唧龄〖孀”這個約束關系的線性公式就如下所示:
// positive values move to the right in left-to-right languages like English.
button2.leading = 1.0 × button1.trailing + 8.0
隨后自動布局就會自動調(diào)整兩個按鈕左右邊緣的位置,直到上述等式左右相等既棺。這里值得注意的是讽挟,自動布局并不是單方面地調(diào)整一個按鈕來滿足條件,而是在需要的時候調(diào)整其中的任意一個援制,甚至兩個按鈕的位置都調(diào)整戏挡。
等式相等意味著,你可以改變item的順序晨仑,也就是說你可以對這個等式做隨意的一次方程計算。經(jīng)過改變拆檬,等式可以更好地表達兩個item之間的約束關系洪己。提醒一句,改變等式別忘了隨之改變multiplier(系數(shù))和constant(常數(shù))竟贯。舉個例子答捕,下面的兩個等式就表達相同的約束:
// 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
另外,約束也不只有兩者相等這一種沃琅,還可以用大于等于(>=)哗咆,或者小于等于(<=)來描述約束關系。約束還有優(yōu)先級益眉,范圍是1~1000晌柬,1000代表必須實現(xiàn)(required),此外都是根據(jù)優(yōu)先級可選擇實現(xiàn)(optional)郭脂。默認優(yōu)先級都是1000年碘。
自動布局實現(xiàn)了所有必須實現(xiàn)的約束之后,會根據(jù)優(yōu)先級順序來嘗試去實現(xiàn)可選約束展鸡。如果實現(xiàn)不了屿衅,就盡可能接近要求,然后繼續(xù)處理下個可選約束莹弊。
通過這套等式涤久、不等式、優(yōu)先級的組合箱硕,你完全可以定義一套極具靈活性的布局拴竹,來讓你的UI元素自適應任何變化。
創(chuàng)建約束
+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format
options:(NSLayoutFormatOptions)opts
metrics:(NSDictionary<NSString *,
id> *)metrics
views:(NSDictionary<NSString *,
id> *)views
根據(jù)Visual Format Language以及對齊選擇項來創(chuàng)建一組對象的約束
+ (instancetype)constraintWithItem:(id)view1
attribute:(NSLayoutAttribute)attr1
relatedBy:(NSLayoutRelation)relation
toItem:(id)view2
attribute:(NSLayoutAttribute)attr2
multiplier:(CGFloat)multiplier
constant:(CGFloat)c
最常用的約束方法剧罩,根據(jù)兩個item的指定attribute來約束item的位置栓拜,返回一個NSLayoutConstraint對象。iOS6.0
參數(shù) | 含義 |
---|---|
view1 | 第一個item |
attr1 | item1的參考屬性 |
relation | 兩個item參考屬性之間的關系惠昔,詳見NSLayoutRelation |
view2 | item1的參照物幕与,item2 |
multiplier | item2的參考屬性帶入計算時需要縮放的倍數(shù) |
c | item2的屬性乘以倍數(shù)之后加上這個常量,來得到約束的最終結果 |
論述:也可能出現(xiàn)這樣的情況镇防,item1的這個約束并不需要參照物item2(比如說約束寬度)啦鸣,這時候在item2上代入nil,attr2代入NSLayoutAttributeNotAnAttribute来氧。
激活或關閉約束
@property(getter=isActive) BOOL active //iOS8.0
這個屬性可以激活或者關閉一個約束诫给,只有激活狀態(tài)的約束才能影響最終的布局。需要注意的是啦扬,如果兩個items的不在同一個界面上中狂,則計算結果會報錯。新創(chuàng)建的約束對象的狀態(tài)默認為關閉扑毡。
你可以在兩個items所在的view上調(diào)用addConstraint:
或者removeConstraint:
來激活或者關閉一個約束胃榕。但更方便的是直接改變這個屬性來替代調(diào)用這兩個方法。
+ (void)activateConstraints:(NSArray<NSLayoutConstraint *> *)constraints //iOS8.0
+ (void)deactivateConstraints:(NSArray<NSLayoutConstraint *> *)constraints //iOS8.0
這兩個方法可以一次性激活/關閉一堆約束的激活狀態(tài)瞄摊。通常來講勋又,用這兩個方法比一個個修改約束的active屬性在性能上更具優(yōu)勢苦掘。
約束內(nèi)部數(shù)據(jù)的接口
@property UILayoutPriority priority //(iOS6.0)
這里再提一遍,約束并不是非真即假的楔壤,而且如果一個約束并不是必須實現(xiàn)的鹤啡,那么自動布局也只會去盡可能貼近等式、不等式的計算結果挺邀。
一個約束被添加并激活了之后揉忘,它的優(yōu)先級就不能在必須實現(xiàn)和可選實現(xiàn)中來回修改了。但是如果同是可選實現(xiàn)的話端铛,還是能夠在約束激活后即時修改優(yōu)先級的具體數(shù)值泣矛。
@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在約束創(chuàng)建之后仍可以修改禾蚕。在現(xiàn)有的約束上修改constant要比移除一個約束您朽,再新建一個除了constant外沒啥區(qū)別的約束要效率得多。
標識一個約束
@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
在習慣由左向右看的地區(qū),相當于NSLayoutAttributeLeft。在習慣從右至左看的地區(qū)誊役,相當于NSLayoutAttributeRight - NSLayoutAttributeTrailing
在習慣由左向右看的地區(qū),相當于NSLayoutAttributeRight讯屈。在習慣從右至左看的地區(qū),相當于NSLayoutAttributeLeft -
magin
一系列邊界約束屬性如下圖所示:
- 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后不使用,直接根據(jù)需要設定約束的priority屬性值即可躁愿。