Masonry 使用

打開Masonry的源代碼,能夠發現兩個屬性php

/*ios

/**git

 * Sets the NSLayoutConstraint multiplier propertygithub

 */框架

- (MASConstraint * (^)(CGFloat multiplier))multipliedBy;less

 

/**dom

 * Sets the NSLayoutConstraint multiplier to 1.0/dividedByiphone

 */ide

- (MASConstraint * (^)(CGFloat divider))dividedBy;函數


*/

multipler屬性表示約束值爲約束對象的乘因數, dividedBy屬性表示約束值爲約束對象的除因數,可用於設置view的寬高比

這兩個屬性能夠設置視圖中的寬高比例

 上代碼。。

 

    [aview makeConstraints:^(MASConstraintMaker *make) {

        make.left.mas_equalTo(self.view);

        make.bottom.mas_equalTo(self.view);

        make.right.mas_equalTo(WeSelf.InputYuYinbtn.left);

        make.height.mas_equalTo(aview.width).multipliedBy(0.6);// 高/寬 == 0.6

    }];

簡要

自動佈局最重要的是約束:UI元素間關係的數學表達式。約束包括尺寸、由優先級和閾值管理的相對位置。它們是添加劑,可能致使約束衝突 、約束不足形成佈局沒法肯定 。這兩種狀況都會產生異常。

使用前:AutoLayout關於更新的幾個方法的區別

  • setNeedsLayout:告知頁面須要更新,可是不會馬上開始更新。執行後會馬上調用layoutSubviews。
  • layoutIfNeeded:告知頁面佈局馬上更新。因此通常都會和setNeedsLayout一塊兒使用。若是但願馬上生成新的frame須要調用此方法,利用這點通常佈局動畫能夠在更新佈局後直接使用這個方法讓動畫生效。
  • layoutSubviews:系統重寫佈局
  • setNeedsUpdateConstraints:告知須要更新約束,可是不會馬上開始
  • updateConstraintsIfNeeded:告知馬上更新約束
  • updateConstraints:系統更新約束

使用

1. 基本使用

  • mas_makeConstraints:添加約束
  • mas_updateConstraints:更新約束、亦可添加新約束
  • mas_remakeConstraints:重置以前的約束

  • multipler屬性表示約束值爲約束對象的乘因數, dividedBy屬性表示約束值爲約束對象的除因數,可用於設置view的寬高比

    // 進行屏幕的適配的時候,每每須要根據屏幕寬度來適配一個相應的高度,在此推薦使用以下約束的方式來進行控件的適配 [self.topView addSubview:self.topInnerView]; [self.topInnerView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.equalTo(self.topView.mas_height).dividedBy(3); make.width.and.height.lessThanOrEqualTo(self.topView); make.width.and.height.equalTo(self.topView).with.priorityLow(); make.center.equalTo(self.topView); }];
  • priorityLow()設置約束優先級
  • #define MAS_SHORTHAND_GLOBALS使用全局宏定義,可使equalTo等效於mas_equalTo
  • #define MAS_SHORTHAND使用全局宏定義, 能夠在調用masonry方法的時候不使用mas_前綴
// 這裏注意到一個地方,就是當使用了這個全局宏定義以後,發現能夠有個類`NSArray+MASAdditions.h`,看了以後發現能夠 self.buttonViews = @[ raiseButton, lowerButton, centerButton ]; // 以後能夠在updateConstraints 方法中 - (void)updateConstraints { [self.buttonViews updateConstraints:^(MASConstraintMaker *make) { make.baseline.equalTo(self.mas_centerY).with.offset(self.offset); }]; [super updateConstraints]; }
  • 動態修改視圖約束:
    // 建立視圖約束 [blueView mas_makeConstraints:^(MASConstraintMaker *make) { self.animatableConstraint = make.edges.equalTo(superview).insets(paddingInsets).priorityLow(); ]]; // 更改約束 (另外一處方法中) UIEdgeInsets paddingInsets = UIEdgeInsetsMake(padding, padding, padding, padding); self.animatableConstraint.insets = paddingInsets; [self layoutIfNeeded];
  • debug模式:
    // 對某個view添加key值 greenView.mas_key = @"greenView"; // 或者以下順序 MASAttachKeys(greenView, redView, blueView, superview); // 一樣的對每條約束亦能夠添加key make.height.greaterThanOrEqualTo(@5000).key(@"ConstantConstraint");
  • preferredMaxLayoutWidth: 多行label的約束問題
// 已經確認好了位置 // 在layoutSubviews中確認label的preferredMaxLayoutWidth值 - (void)layoutSubviews { [super layoutSubviews]; // 你必須在 [super layoutSubviews] 調用以後,longLabel的frame有值以後設置preferredMaxLayoutWidth self.longLabel.preferredMaxLayoutWidth = self.frame.size.width-100; // 設置preferredLayoutWidth後,須要從新佈局 [super layoutSubviews]; }
  • scrollView使用約束的問題:原理經過一個contentView來約束scrollView的contentSize大小,也就是說以子控件的約束條件,來控制父視圖的大小
// 1. 控制scrollView大小(顯示區域) [self.scrollView makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view); }]; // 2. 添加一個contentView到scrollView,而且添加好約束條件 [contentView makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.scrollView); // 注意到此處的寬度約束條件,這個寬度的約束條件是比添加項 make.width.equalTo(self.scrollView); }]; // 3. 對contentView的子控件作好約束,達到能夠控制contentView的大小
  • 新方法:2個或2個以上的控件等間隔排序
/** * 多個控件固定間隔的等間隔排列,變化的是控件的長度或者寬度值 * * @param axisType 軸線方向 * @param fixedSpacing 間隔大小 * @param leadSpacing 頭部間隔 * @param tailSpacing 尾部間隔 */ - (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedSpacing:(CGFloat)fixedSpacing l eadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing; /** * 多個固定大小的控件的等間隔排列,變化的是間隔的空隙 * * @param axisType 軸線方向 * @param fixedItemLength 每一個控件的固定長度或者寬度值 * @param leadSpacing 頭部間隔 * @param tailSpacing 尾部間隔 */ - (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedItemLength:(CGFloat)fixedItemLength leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;

使用方法很簡單,由於它是NSArray的類擴展:

// 建立水平排列圖標 arr中放置了2個或連個以上的初始化後的控件 // alongAxis 軸線方向 固定間隔 頭部間隔 尾部間隔 [arr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:20 leadSpacing:5 tailSpacing:5]; [arr makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(@60); make.height.equalTo(@60); }];

2. 注意事項

  • 約束視圖對象只有在被addSubview以後,才能給視圖添加約束
  • 當你的全部約束都在 updateConstraints 內調用的時候,你就須要在此調用此方法,由於 updateConstraints方法是須要觸發的
// 調用在view 內部,而不是viewcontroller + (BOOL)requiresConstraintBasedLayout { return YES; } /** * 蘋果推薦 約束 增長和修改 放在此方法種 */ - (void)updateConstraints { [self.growingButton updateConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self); make.width.equalTo(@(self.buttonSize.width)).priorityLow(); make.height.equalTo(@(self.buttonSize.height)).priorityLow(); make.width.lessThanOrEqualTo(self); make.height.lessThanOrEqualTo(self); }]; //最後記得回調super方法 [super updateConstraints]; }
  • 若是想要約束變換以後實現動畫效果,則須要執行以下操做
    // 通知須要更新約束,可是不當即執行 [self setNeedsUpdateConstraints]; // 當即更新約束,以執行動態變換 // update constraints now so we can animate the change [self updateConstraintsIfNeeded]; // 執行動畫效果, 設置動畫時間 [UIView animateWithDuration:0.4 animations:^{ [self layoutIfNeeded]; }];



文/碼碼樂趣(簡書做者)
原文連接:http://www.jianshu.com/p/1d1a1165bb04
著做權歸做者全部,轉載請聯繫做者得到受權,並標註「簡書做者」。

 

1
MagicNumber -> autoresizingMask -> autolayout

以上是純手寫代碼所經歷的關於頁面佈局的三個時期

在iphone1-iphone3gs時代 window的size固定爲(320,480) 咱們只須要簡單計算一下相對位置就行了

在iphone4-iphone4s時代 蘋果推出了retina屏 可是給了碼農們很是大的福利:window的size不變

在iphone5-iphone5s時代 window的size變了(320,568) 這時autoresizingMask派上了用場(爲啥這時候不用Autolayout? 由於還要支持ios5唄) 簡單的適配一下便可

在iphone6+時代 window的width也發生了變化(相對5和5s的屏幕比例沒有變化) 終因而時候拋棄autoresizingMask改用autolayout了(不用支持ios5了 相對於屏幕適配的多樣性來講autoresizingMask也已通過時了)

那如何快速的上手autolayout呢? 說實話 當年ios6推出的同時新增了autolayout的特性 我看了一下官方文檔和demo 就立馬拋棄到一邊了 由於實在過於的繁瑣和囉嗦(有過經驗的朋友確定有同感)

直到iPhone6發佈以後 我知道使用autolayout勢在必行了 這時想起了之前在瀏覽Github看到過的一個第三方庫Masonry 在花了幾個小時的研究使用後 我就將autolayout掌握了(重點是我並無學習任何的官方文檔或者其餘的關於autolayout的知識) 這就是我爲何要寫下這篇文章來推薦它的緣由.

介紹

Masonry 源碼:https://github.com/Masonry/Masonry

Masonry是一個輕量級的佈局框架 擁有本身的描述語法 採用更優雅的鏈式語法封裝自動佈局 簡潔明瞭 並具備高可讀性 並且同時支持 iOS 和 Max OS X。

咱們先來看一段官方的sample code來認識一下Masonry

1
2
3
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
     make.edges.equalTo(superview). with .insets(padding);
}];

看到block裏面的那句話: make edges equalTo superview with insets

經過鏈式的天然語言 就把view1給autolayout好了 是否是簡單易懂?

使用

看一下Masonry支持哪一些屬性

1
2
3
4
5
6
7
8
9
10
11
@property (nonatomic, strong, readonly) MASConstraint *left;
@property (nonatomic, strong, readonly) MASConstraint *top;
@property (nonatomic, strong, readonly) MASConstraint *right;
@property (nonatomic, strong, readonly) MASConstraint *bottom;
@property (nonatomic, strong, readonly) MASConstraint *leading;
@property (nonatomic, strong, readonly) MASConstraint *trailing;
@property (nonatomic, strong, readonly) MASConstraint *width;
@property (nonatomic, strong, readonly) MASConstraint *height;
@property (nonatomic, strong, readonly) MASConstraint *centerX;
@property (nonatomic, strong, readonly) MASConstraint *centerY;
@property (nonatomic, strong, readonly) MASConstraint *baseline;

這些屬性與NSLayoutAttrubute的對照表以下

43.jpg

其中leading與left trailing與right 在正常狀況下是等價的 可是當一些佈局是從右至左時(好比阿拉伯文?沒有相似的經驗) 則會對調 換句話說就是基本能夠不理不用 用left和right就行了

在ios8發佈後 又新增了一堆奇奇怪怪的屬性(有興趣的朋友能夠去瞅瞅) Masonry暫時還不支持(不過你要支持ios6,ios7 就不必去管那麼多了)

在講實例以前 先介紹一個MACRO

1
#define WS(weakSelf)  __weak __typeof(&*self)weakSelf = self;

快速的定義一個weakSelf 固然是用於block裏面啦 下面進入正題(爲了方便 咱們測試的superView都是一個size爲(300,300)的UIView)

下面 經過一些簡單的實例來簡單介紹如何輕鬆愉快的使用Masonry:

1. [基礎] 居中顯示一個view

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void)viewDidLoad
{
     [ super  viewDidLoad];
     // Do any additional setup after loading the view.
     
     WS(ws);
     
     UIView *sv = [UIView  new ];
     [sv showPlaceHolder];
     sv.backgroundColor = [UIColor blackColor];
     [self.view addSubview:sv];
     [sv mas_makeConstraints:^(MASConstraintMaker *make) {
         make.center.equalTo(ws.view);
         make.size.mas_equalTo(CGSizeMake(300, 300));
     }];
     
}

代碼效果

04.PNG

 

使用我之間寫的MMPlaceHolder 能夠看到superview已經按照咱們預期居中而且設置成了適當的大小

那麼先看看這幾行代碼

1
2
3
4
5
6
7
8
9
10
11
12
//今後之後基本能夠拋棄CGRectMake了
UIView *sv = [UIView  new ];
//在作autoLayout以前 必定要先將view添加到superview上 不然會報錯
[self.view addSubview:sv];
//mas_makeConstraints就是Masonry的autolayout添加函數 將所需的約束添加到block中行了
[sv mas_makeConstraints:^(MASConstraintMaker *make) {
//將sv居中(很容易理解吧?)
     make.center.equalTo(ws.view);
     
     //將size設置成(300,300)
     make.size.mas_equalTo(CGSizeMake(300, 300));
}];

這裏有兩個問題要分解一下

首先在Masonry中可以添加autolayout約束有三個函數

1
2
3
4
5
6
7
8
9
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))block;
- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block;
- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block;
/*
mas_makeConstraints 只負責新增約束 Autolayout不能同時存在兩條針對於同一對象的約束 不然會報錯 
mas_updateConstraints 針對上面的狀況 會更新在block中出現的約束 不會致使出現兩個相同約束的狀況
mas_remakeConstraints 則會清除以前的全部約束 僅保留最新的約束
三種函數善加利用 就能夠應對各類狀況了
*/

其次 equalTo 和 mas_equalTo的區別在哪裏呢? 其實 mas_equalTo是一個MACRO

1
2
3
4
#define mas_equalTo(...)                 equalTo(MASBoxValue((__VA_ARGS__)))
#define mas_greaterThanOrEqualTo(...)    greaterThanOrEqualTo(MASBoxValue((__VA_ARGS__)))
#define mas_lessThanOrEqualTo(...)       lessThanOrEqualTo(MASBoxValue((__VA_ARGS__)))
#define mas_offset(...)                  valueOffset(MASBoxValue((__VA_ARGS__)))

能夠看到 mas_equalTo只是對其參數進行了一個BOX操做(裝箱) MASBoxValue的定義具體能夠看看源代碼 太長就不貼出來了

所支持的類型 除了NSNumber支持的那些數值類型以外 就只支持CGPoint CGSize UIEdgeInsets

介紹完這幾個問題 咱們就繼續往下了 PS:剛纔定義的sv會成爲咱們接下來全部sample的superView

2. [初級] 讓一個view略小於其superView(邊距爲10)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
UIView *sv1 = [UIView  new ];
[sv1 showPlaceHolder];
sv1.backgroundColor = [UIColor redColor];
[sv addSubview:sv1];
[sv1 mas_makeConstraints:^(MASConstraintMaker *make) {
     make.edges.equalTo(sv). with .insets(UIEdgeInsetsMake(10, 10, 10, 10));
     
     /* 等價於
     make.top.equalTo(sv).with.offset(10);
     make.left.equalTo(sv).with.offset(10);
     make.bottom.equalTo(sv).with.offset(-10);
     make.right.equalTo(sv).with.offset(-10);
     */
     
     /* 也等價於
     make.top.left.bottom.and.right.equalTo(sv).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
     */
}];

代碼效果

05.PNG

能夠看到 edges 其實就是top,left,bottom,right的一個簡化 分開寫也能夠 一句話更省事

那麼爲何bottom和right裏的offset是負數呢? 由於這裏計算的是絕對的數值 計算的bottom須要小魚sv的底部高度 因此要-10 同理用於right

這裏有意思的地方是and和with 其實這兩個函數什麼事情都沒作

1
2
3
4
5
6
- (MASConstraint *) with  {
     return  self;
}
- (MASConstraint *)and {
     return  self;
}

可是用在這種鏈式語法中 就很是的巧妙和易懂 不得不佩服做者的心思(雖然我如今基本都會省略)

3. [初級] 讓兩個高度爲150的view垂直居中且等寬且等間隔排列 間隔爲10(自動計算其寬度)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int padding1 = 10;
[sv2 mas_makeConstraints:^(MASConstraintMaker *make) {
     make.centerY.mas_equalTo(sv.mas_centerY);
     make.left.equalTo(sv.mas_left). with .offset(padding1);
     make.right.equalTo(sv3.mas_left). with .offset(-padding1);
     make.height.mas_equalTo(@150);
     make.width.equalTo(sv3);
}];
[sv3 mas_makeConstraints:^(MASConstraintMaker *make) {
     make.centerY.mas_equalTo(sv.mas_centerY);
     make.left.equalTo(sv2.mas_right). with .offset(padding1);
     make.right.equalTo(sv.mas_right). with .offset(-padding1);
     make.height.mas_equalTo(@150);
     make.width.equalTo(sv2);
}];

代碼效果

06.PNG

這裏咱們在兩個子view之間互相設置的約束 能夠看到他們的寬度在約束下自動的被計算出來了

4. [中級] 在UIScrollView順序排列一些view並自動計算contentSize

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
UIScrollView *scrollView = [UIScrollView  new ];
scrollView.backgroundColor = [UIColor whiteColor];
[sv addSubview:scrollView];
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
     make.edges.equalTo(sv). with .insets(UIEdgeInsetsMake(5,5,5,5));
}];
UIView *container = [UIView  new ];
[scrollView addSubview:container];
[container mas_makeConstraints:^(MASConstraintMaker *make) {
     make.edges.equalTo(scrollView);
     make.width.equalTo(scrollView);
}];
int count = 10;
UIView *lastView = nil;
for  ( int i = 1 ; i <= count ; ++i )
{
     UIView *subv = [UIView  new ];
     [container addSubview:subv];
     subv.backgroundColor = [UIColor colorWithHue:( arc4random() % 256 / 256.0 )
                                       saturation:( arc4random() % 128 / 256.0 ) + 0.5
                                       brightness:( arc4random() % 128 / 256.0 ) + 0.5
                                            alpha:1];
     
     [subv mas_makeConstraints:^(MASConstraintMaker *make) {
         make.left.and.right.equalTo(container);
         make.height.mas_equalTo(@(20*i));
         
         if  ( lastView )
         {
             make.top.mas_equalTo(lastView.mas_bottom);
         }
         else
         {
             make.top.mas_equalTo(container.mas_top);
         }
     }];
     
     lastView = subv;
}
[container mas_makeConstraints:^(MASConstraintMaker *make) {
     make.bottom.equalTo(lastView.mas_bottom);
}];

頭部效果

07.PNG

 

尾部效果

08.PNG

從scrollView的scrollIndicator能夠看出 scrollView的內部已如咱們所想排列好了

這裏的關鍵就在於container這個view起到了一箇中間層的做用 可以自動的計算uiscrollView的contentSize

5. [高級] 橫向或者縱向等間隙的排列一組view

很遺憾 autoLayout並無直接提供等間隙排列的方法(Masonry的官方demo中也沒有對應的案例) 可是參考案例3 咱們能夠經過一個小技巧來實現這個目的 爲此我寫了一個Category

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
@implementation UIView(Masonry_LJC)
- (void) distributeSpacingHorizontallyWith:(NSArray*)views
{
     NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count+1];
     
     for  ( int i = 0 ; i < views.count+1 ; ++i )
     {
         UIView *v = [UIView  new ];
         [spaces addObject:v];
         [self addSubview:v];
         
         [v mas_makeConstraints:^(MASConstraintMaker *make) {
             make.width.equalTo(v.mas_height);
         }];
     }    
     
     UIView *v0 = spaces[0];
     
     __weak __typeof(&*self)ws = self;
     
     [v0 mas_makeConstraints:^(MASConstraintMaker *make) {
         make.left.equalTo(ws.mas_left);
         make.centerY.equalTo(((UIView*)views[0]).mas_centerY);
     }];
     
     UIView *lastSpace = v0;
     for  ( int i = 0 ; i < views.count; ++i )
     {
         UIView *obj = views[i];
         UIView *space = spaces[i+1];
         
         [obj mas_makeConstraints:^(MASConstraintMaker *make) {
             make.left.equalTo(lastSpace.mas_right);
         }];
         
         [space mas_makeConstraints:^(MASConstraintMaker *make) {
             make.left.equalTo(obj.mas_right);
             make.centerY.equalTo(obj.mas_centerY);
             make.width.equalTo(v0);
         }];
         
         lastSpace = space;
     }
     
     [lastSpace mas_makeConstraints:^(MASConstraintMaker *make) {
         make.right.equalTo(ws.mas_right);
     }];
     
}
- (void) distributeSpacingVerticallyWith:(NSArray*)views
{
     NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count+1];
     
     for  ( int i = 0 ; i < views.count+1 ; ++i )
     {
         UIView *v = [UIView  new ];
         [spaces addObject:v];
         [self addSubview:v];
         
         [v mas_makeConstraints:^(MASConstraintMaker *make) {
             make.width.equalTo(v.mas_height);
         }];
     }
     
     
     UIView *v0 = spaces[0];
     
     __weak __typeof(&*self)ws = self;
     
     [v0 mas_makeConstraints:^(MASConstraintMaker *make) {
         make.top.equalTo(ws.mas_top);
         make.centerX.equalTo(((UIView*)views[0]).mas_centerX);
     }];
     
     UIView *lastSpace = v0;
     for  ( int i = 0 ; i < views.count; ++i )
     {
         UIView *obj = views[i];
         UIView *space = spaces[i+1];
         
         [obj mas_makeConstraints:^(MASConstraintMaker *make) {
             make.top.equalTo(lastSpace.mas_bottom);
         }];
         
         [space mas_makeConstraints:^(MASConstraintMaker *make) {
             make.top.equalTo(obj.mas_bottom);
             make.centerX.equalTo(obj.mas_centerX);
             make.height.equalTo(v0);
         }];
         
         lastSpace = space;
     }
     
     [lastSpace mas_makeConstraints:^(MASConstraintMaker *make) {
         make.bottom.equalTo(ws.mas_bottom);
     }];
}
@end

簡單的來測試一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
UIView *sv11 = [UIView  new ];
UIView *sv12 = [UIView  new ];
UIView *sv13 = [UIView  new ];
UIView *sv21 = [UIView  new ];
UIView *sv31 = [UIView  new ];
sv11.backgroundColor = [UIColor redColor];
sv12.backgroundColor = [UIColor redColor];
sv13.backgroundColor = [UIColor redColor];
sv21.backgroundColor = [UIColor redColor];
sv31.backgroundColor = [UIColor redColor];
[sv addSubview:sv11];
[sv addSubview:sv12];
[sv addSubview:sv13];
[sv addSubview:sv21];
[sv addSubview:sv31];
//給予不一樣的大小 測試效果
[sv11 mas_makeConstraints:^(MASConstraintMaker *make) {
     make.centerY.equalTo(@[sv12,sv13]);
     make.centerX.equalTo(@[sv21,sv31]);
     make.size.mas_equalTo(CGSizeMake(40, 40));
}];
[sv12 mas_makeConstraints:^(MASConstraintMaker *make) {
     make.size.mas_equalTo(CGSizeMake(70, 20));
}];
[sv13 mas_makeConstraints:^(MASConstraintMaker *make) {
     make.size.mas_equalTo(CGSizeMake(50, 50));
}];
[sv21 mas_makeConstraints:^(MASConstraintMaker *make) {
     make.size.mas_equalTo(CGSizeMake(50, 20));
}];
[sv31 mas_makeConstraints:^(MASConstraintMaker *make) {
     make.size.mas_equalTo(CGSizeMake(40, 60));
}];
[sv distributeSpacingHorizontallyWith:@[sv11,sv12,sv13]];
[sv distributeSpacingVerticallyWith:@[sv11,sv21,sv31]];
[sv showPlaceHolderWithAllSubviews];
[sv hidePlaceHolder];

代碼效果

09.PNG

perfect! 簡潔明瞭的達到了咱們所要的效果

這裏所用的技巧就是 使用空白的佔位view來填充咱們目標view的旁邊 這點經過圖上的空白標註能夠看出來

小結

經過以上5個案例 我以爲已經把Masonry的經常使用功能介紹得差很少了 若是你以爲意猶未盡呢 請下載官方的demo來學習

總而言之 Masonry是一個很是優秀的autolayout庫 可以節省大量的開發和學習時間 尤爲適合我這種純代碼的iOSer 在iPhone6發佈後引起的適配潮中 Masonry必定能夠助你一臂之力 :)

 

 

 

 

 

iOS Autolayout之Masonry解讀

字數2609 閱讀19472 評論58 

Masonry

  • Masonry是公認很是簡潔優美的一款Autolayout框架
  • 我推薦你們重點學習這個框架
  • 我會把Autolayout的思惟融合這個框架一塊兒講解

    Masonry的使用

  • 想要使用第三方Masonry要麼要去GitHub上下載原代碼下來拖進項目中,要麼就直接使用cocoapods,pod search Masonry,下載最新版
  • cocoapods的使用不是本文討論的範圍,你們能夠百度一下哈,安裝很是簡單

    Masonry的講解

  • 由於以前的一篇關於VFL的文章我自我感受寫的不是太好,其實主要緣由是VFL的約束建立很是宏觀,若是既要照顧語法講解,又要照顧約束理解,反而介紹會使文章增長不少口水話,長而乏味
  • Masonry的約束添加思惟其實與蘋果原API的添加思惟是相同的,只是Masonry語法更簡潔,代碼更優美
  • 在這裏,爲了融合Autolayout的思想,我依然要說下面幾點
    • Autolayout所倡導的兩個核心詞是約束,參照
    • 而我認爲,Autolayout其實核心思想仍是爲了設置frame
    • 不管咱們如何添加約束,最終仍是爲了肯定其位置尺寸
    • 因此,Autolayout的關鍵就是如何設置約束,讓空間知足位置,尺寸這兩個必要條件
    • 還有就是,當一個控件的約束已經可以知足上述兩個條件了,就不要再添加多餘的約束了,很容易會照成約束衝突
    • 除非你想設置其餘優先級的約束
    • 優先級會在例子中說明其用處

      例子講解

  • 因爲Masonry是重點推薦的,我會分別用三個例子來說訴它
    第一個例子
  • 這個例子很簡單,僅僅是爲了向你們介紹Masonry的語法
  • 比起文字闡述需求,我不如直接上圖讓你們看得更直接明白
  • 實現後的效果是這樣的

 


圖1
  • ok,接下來看看怎麼用代碼去實現這個效果
  • 先添加四個View

    UIView *redView = [[UIView alloc]init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; UIView *blueView = [[UIView alloc]init]; blueView.backgroundColor = [UIColor blueColor]; [self.view addSubview:blueView]; UIView *yellow = [[UIView alloc]init]; yellow.backgroundColor = [UIColor yellowColor]; [self.view addSubview:yellow]; UIView *green = [[UIView alloc]init]; green.backgroundColor = [UIColor greenColor]; [self.view addSubview:green];
  • 建立添加紅色View的約束
    • 先來看看語法
    • Masonry的語法可讀性很是強
    • 因此我不會在這裏死板的一個單詞一個單詞的介紹
    • 你們在寫的時候徹底就能夠像寫句子同樣,而且Masonry添加約束都是mas_makeConstraints這個方法
    • 只須要在塊中寫上想好的約束
    • 好比下面的第一個約束
    • 翻譯過來就是使左邊等於self.view的左邊,間距爲0
    • 而在塊中主語就是調用者,這裏也就是redView
    • 因此使用Masonry,你就想着是用英語在造句就好了,哈哈
    • 還有一點,andwith其實就是get調用者自己,裏面僅僅是return self
[redView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.view.mas_left).offset(0);//使左邊等於self.view的左邊,間距爲0 make.top.equalTo(self.view.mas_top).offset(0);//使頂部與self.view的間距爲0 make.width.equalTo(self.view.mas_width).multipliedBy(0.5);//設置寬度爲self.view的一半,multipliedBy是倍數的意思,也就是,使寬度等於self.view寬度的0.5倍 make.height.equalTo(self.view.mas_height).multipliedBy(0.5);//設置高度爲self.view高度的一半 }];
  • 上面我已經添加了redView的約束,它已經擁有了寬和高,還有水平方向和垂直方向的位置,也就是frame中的x,y,width,height,都有了
  • 因此redView的約束就添加完成了,無需再添加過多的約束
  • 其餘的view將要以它爲錨點,來添加約束,肯定自身的位置尺寸
  • 接下來設置blueView的約束
  • 你們在看下面代碼以前能夠本身思考,按照圖1中的blueView的效果,咱們應當怎樣添加約束呢?
  • 很明顯,只須要與紅色等寬高,而且與紅色左間距爲0,頂部對齊,就能夠了
[blueView mas_makeConstraints:^(MASConstraintMaker *make) { make.width.and.height.equalTo(redView);//使寬高等於redView make.top.equalTo(redView.mas_top);//與redView頂部對齊 make.leading.equalTo(redView.mas_right);//與redView的間距爲0 }];
  • 剩下的兩個View的約束我就不過多的闡述了,你們能夠本身先想一下怎麼添加約束,再來看我代碼是怎麼實現的
  • 固然,極可能你的想法和個人實現不同,這是很正常的,約束的實現方法有太多了
  • 可是萬變不離其宗!必定得保證最終設置完畢後,全部的控件都擁有了位置尺寸
[yellow mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.equalTo(redView);//與redView左對齊 make.top.equalTo(redView.mas_bottom);//與redView底部間距爲0 make.width.and.height.equalTo(redView);//與redView寬高相等 }]; [green mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(yellow.mas_right);//與yellow右邊間距爲0 make.top.equalTo(blueView.mas_bottom);//與blueView底部間距爲0 make.width.and.height.equalTo(redView);//與redView等寬高 }];
第二個例子
  • 這個例子我但願你們能對約束的理念有個更深的理解
  • 由於我一路寫下來,一直用的都是固定尺寸的例子,或者是固定位置的例子,我怕誤導你們認爲Autolayout是很是死板的,必須把每一個控件的約束添加到知足位置尺寸,再去添加其餘控件的約束,這樣纔不會出錯
  • 其實不是這樣的,的確,在全部控件添加完約束後,得擁有本身的位置尺寸,可是有時這兩個必須條件能夠利用相對來知足
  • 接下來我就用例子來解釋吧
  • 先讓你們看一下效果圖

 


豎屏

 


橫屏
  • 正如你們在圖片所看到的,我但願兩個等寬高的紅色方塊可以在屏幕旋轉的時候,間距等比例縮放,它們的相對位置是固定的,絕對位置隨着屏幕的寬改變而改變
  • 其餘三個灰色的方塊,它們的寬是不肯定,這就是我想要和你們說的相對概念
  • 我並無固定死灰色方塊的寬度,只要求它們與紅色方塊的間距爲0,而且灰色方塊的寬度相等
  • 可是紅色方塊的寬度是固定的,灰色方塊就會互相相等的寬度,填充着紅色方塊間的空隙
  • 接下來看看代碼是怎麼實現的吧
  • 添加View的代碼我就不上了,直接看添加約束的代碼
//代碼中View的順序與圖中從左到右的View的順序一致 //例子中,惟一不肯定的就是灰色View的寬度,咱們先把肯定的約束給一個一個的添加上來 //灰1左間距、高度、垂直位置(由於和紅1底部對齊)是肯定的,添加約束 [gray1 mas_makeConstraints:^(MASConstraintMaker *make) { make.height.mas_equalTo(20); make.leading.equalTo(self.view.mas_leading).offset(0); make.bottom.equalTo(red1.mas_bottom); }]; //紅1,寬高、左間距、底間距是肯定的,添加約束 [red1 mas_makeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(100); make.height.mas_equalTo(50); make.left.equalTo(gray1.mas_right); make.bottom.equalTo(self.view.mas_bottom).offset(-50); }]; //灰2,左間距、高度、垂直位置是肯定的,寬度要與灰1一致,是爲了能均勻填充,添加約束 [gray2 mas_makeConstraints:^(MASConstraintMaker *make) { make.height.and.width.equalTo(gray1); make.leading.equalTo(red1.mas_right); make.bottom.equalTo(red1.mas_bottom); }]; //紅2,寬高、左間距、底間距是肯定的,添加約束 [red2 mas_makeConstraints:^(MASConstraintMaker *make) { make.height.and.width.equalTo(red1); make.leading.equalTo(gray2.mas_right); make.bottom.equalTo(red1.mas_bottom); }]; //灰3,左間距、右間距、高度、垂直位置是肯定的,添加約束 [gray3 mas_makeConstraints:^(MASConstraintMaker *make) { make.height.and.width.equalTo(gray1); make.leading.equalTo(red2.mas_right); make.trailing.equalTo(self.view.mas_right); make.bottom.equalTo(red1.mas_bottom); }];
  • 你們看了上面的講解後,會發現三個灰色方塊都沒有設置固定的寬
  • 可是它們三個都等寬,紅色方塊又是固定的,那麼在這5個View間距都爲0的狀況下,灰色方塊不就會去擠壓紅色方塊,直到灰色方塊寬度相等,那麼紅色方塊也處在了應有的位置麼
  • 這就是我想說的相對,紅色方塊寬度是固定的,那麼水平方向上的間距就須要剩下的三個灰色方塊去填充,當界面橫屏時,三個灰色方塊爲了相對自身寬度要相同,相對紅色邊界,self.view邊界,間距保持爲0,那麼就得犧牲自身寬度的穩定,去維持這些相對的約束
  • 但願我這些話能幫助你們更深入的理解約束,更多的東西須要你們去作項目慢慢體會
第三個例子
  • 最後這個例子是老例子了,我想給你們看看其實Masonry作動畫也和其餘的Autolayout方法同樣,可是添加約束的代碼卻很是的少,能夠和我以前的另外一篇文章比較一下
  • 裏面的約束我就不講解了,看了上面的代碼,下面的約束對你來講確定是小菜一碟
  • 約束代碼
UIView *redView = [[UIView alloc]init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; UIView *greenView = [[UIView alloc]init]; greenView.backgroundColor = [UIColor greenColor]; [self.view addSubview:greenView]; UIView *blueView = [[UIView alloc]init]; blueView.backgroundColor = [UIColor blueColor]; [self.view addSubview:blueView]; [redView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.view.mas_left).offset(20); make.bottom.equalTo(self.view.mas_bottom).offset(-20); make.width.equalTo(self.view.mas_width).multipliedBy(0.2); make.height.equalTo(self.view.mas_height).multipliedBy(0.2); }]; [greenView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(redView.mas_right).offset(20); make.bottom.equalTo(self.view.mas_bottom).offset(-20); make.width.equalTo(self.view.mas_width).multipliedBy(0.2); make.height.equalTo(self.view.mas_height).multipliedBy(0.2); }]; [blueView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(greenView.mas_right).offset(20); make.bottom.equalTo(self.view.mas_bottom).offset(-20); make.width.equalTo(self.view.mas_width).multipliedBy(0.2); make.height.equalTo(self.view.mas_height).multipliedBy(0.2); make.left.equalTo(redView.mas_right).offset(20).priority(250); }];
  • 動畫代碼
[self.greenView removeFromSuperview]; [UIView animateWithDuration:1.0f animations:^{ [self.view layoutIfNeeded]; }];

 


動畫前

 


動畫後
  • 好了,Masonry就爲你們講解到這裏,若是對Masonry的使用語法或者是對約束的思想還有什麼不理解,但願您能夠不吝惜的提出來,我但願能把文章作得更通俗易懂,更深入!
相關文章
相關標籤/搜索