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的使用语法或者是对约束的思想还有什么不理解,但愿您能够不吝惜的提出来,我但愿能把文章作得更通俗易懂,更深入!
相关文章
相关标签/搜索