有感于iOS自動布局代碼的冗長和繁瑣,閑來無事,便自己封裝了一下。
寫的過程中我借鑒了NSLayoutAnchor和masonry的一些思路议薪,寫了充分的單元測試用例,并對框架的性能(耗時和內(nèi)存占用)做了一個簡單評估媳友。
優(yōu)點
- 簡單斯议,17KB大小。易用庆锦,對于許多布局捅位,用起來跟frame差不多
- 支持iOS8和swift
- 速度是masonry的1.7倍轧葛,接近系統(tǒng)方法速度搂抒,占用內(nèi)存小
- 跟蹤所有約束艇搀,不需要額外寫成員屬性引用約束
- 充分的單元測試
- 支持iOS11,相對safeAreaLayoutGuide的布局約束書寫非常簡便求晶!
設(shè)置約束
所有約束設(shè)置都遵循系統(tǒng)的公式:
firstItem.firstAttribute {=,<=,>=} secondItem.secondAttribute * multiplier + constant
簡便寫法(適用于NSLayoutRelationEqual、multiplier = 1 且除了寬芳杏、高以外的約束的constant = 0的情況)
[self.redView activateConstraints:^{
self.redView.height_attr.constant = 100; // redView的高度 = 100
self.redView.width_attr = self.blueView.width_attr; // redView的寬度 = blueView的寬度
self.redView.top_attr = self.blueView.top_attr; // redView的頂部 = blueView的頂部
self.redView.left_attr = self.blueView.right_attr; // redView的左邊 = blueView的右邊
}];
常規(guī)寫法
[self.redView activateConstraints:^{
self.redView.height_attr.constant = 150; // redView的高度 = 150
[self.redView.width_attr equalTo:self.blueView.width_attr constant:50]; // redView的寬度 = blueView的寬度 + 50
[self.redView.top_attr equalTo:self.blueView.top_attr constant:-10]; // redView的頂部 = blueView的頂部 - 10
[self.redView.left_attr greaterThan:self.blueView.right_attr constant:20]; // redView的左邊 >= blueView的右邊 + 20
}];
activateConstraints方法會將block里所有約束都綁定給調(diào)用者矩屁,這里就是self.redView,這么做是為了方便以后獲取約束爵赵。
也可以用更接近系統(tǒng)的風(fēng)格設(shè)置約束吝秕,但這樣以后想獲取特定的某個約束就比較麻煩,需要創(chuàng)建一個成員變量引用以后想改變的約束空幻。
NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:4];
[arrayM addObject:[self.redView.height_attr equalTo:nil constant:100]];
[arrayM addObject:[self.redView.width_attr equalTo:self.blueView.width_attr]];
[arrayM addObject:[self.redView.top_attr equalTo:self.blueView.top_attr]];
[arrayM addObject:[self.redView.left_attr equalTo:self.blueView.right_attr]];
[NSLayoutConstraint activateConstraints:arrayM];
更新safeAreaLayoutGuide布局寫法烁峭,不需要寫版本判斷
[self.redView activateConstraints:^{
self.redView.height_attr.constant = 100; // redView的高度 = 100
self.redView.width_attr = self.blueView.width_attr; // redView的寬度 = blueView的寬度
self.redView.top_attr = self.view.top_attr_safe; // redView的頂部 = view的safeAreaLayoutGuide的頂部,非iOS11則是view的頂部
self.redView.left_attr = self.view.right_attr_safe; // redView的左邊 = view的safeAreaLayoutGuide的右邊秕铛,非iOS11則是view的右邊
}];
改變約束值
self.blueView.width_attr.constant = 100;
或者
[self.redView constraintAccordingToAttribute:self.redView.height_attr].constant = 100;
獲取約束
獲取非常方便约郁,當(dāng)初創(chuàng)建約束是怎樣的相對關(guān)系,通過相同的關(guān)系就可以獲取約束但两。
NSLayoutConstraint *cons = [self.titleLabel constraintAccordingToAttribute:self.titleLabel.bottom_attr andAttribute:self.subtitleLabel.top_attr];
激活和關(guān)閉約束
[self.redView activateConstraintAccordingToAttribute:self.redView.height_attr];
[self.redView deactivateConstraintAccordingToAttribute:self.redView.height_attr];
注意:調(diào)用deactivateConstraintAccordingToAttribute會將該約束對象銷毀鬓梅,這里保持跟系統(tǒng)的deactivateConstraint方法一致。如果只是想暫時關(guān)閉約束谨湘,以后想再activate绽快,則應(yīng)該獲取約束后,設(shè)置.active = NO
解釋一下核心方法 -(void)activateConstraints:(void (^)())constraints悲关;
這是UIView的一個對象方法谎僻,一般來說每個UIView的布局代碼寫在自己的block里, 只有調(diào)一次該方法寓辱,才會給這個方法的調(diào)用者創(chuàng)建一個用來引用布局對象的可變數(shù)組艘绍,以后才可以通過這個調(diào)用者拿到里面的布局對象。
并且只要調(diào)用了一次該方法秫筏,以后即使不在該方法的block里寫的約束诱鞠,約束的firstItem如果和該方法的調(diào)用者是一個對象,也會把這個約束添加到firstItem(調(diào)用者)的數(shù)組里这敬。
如果調(diào)用了activateConstraints后航夺,又希望移除對應(yīng)view的數(shù)組,可以調(diào)用
- (void)deactivateAllConstraintsAndAssociatedObjects
具體使用請移步github下載示例代碼崔涂。
添加到項目
使用CocoaPods
在podfile中加入 'NSLayoutConstraint-SSLayout'
直接使用源代碼
將Source文件夾下的文件copy到項目