iOS常用第三方库之Masonry

一、前言

关于苹果的布局一直是我比较纠结的问题,是写代码来控制布局,还是使用storyboard来控制布局呢?以前我个人开发的时候很少使用代码去写约束,因为太麻烦了。所以最终选择的都是AutoLayout进行布局,然后拖线设置约束。不过好多公司进行iOS开发的时候都会去动态的修改约束,而且有的会使用约束去创建一些动画,所以不太去用storyboard进行开发(还有就是使用storyboard几个人合作的时候比较麻烦)。反倒更多的是写代码开发看起来更加的高效。所以好多开发者都开始去使用Masonry。它是一个封装的第三方类库,作用就是来简化开发者写布局约束。

二、“安装”Masonry

因为它是一个第三方的类库,我们可以从这里下载,然后解压将Masonry那个文件夹拖入自己的项目文件夹下即可。

三、开始使用Masonry

我们在使用它的时候,最好在AppDelegate.m的

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

方法中去自定义加载自己的控制器。例如我写的时候就是这样:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

self.window.backgroundColor = [UIColor whiteColor];

UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];

self.window.rootViewController = nav;

[self.window makeKeyAndVisible];

return YES;

}

直接加载的我自己写的ViewController。(建议把系统自带的Main.stoaryboard删除掉,如果运行报错自己修改,问题不大)。

先来一个不用Masonry写的最简单的布局:(目的是在视图中添加一个视图)

- (void)viewDidLoad {

[super viewDidLoad];

self.title  = @"Basic View";

UIView *view1 = [[UIView alloc] init];

view1.translatesAutoresizingMaskIntoConstraints = NO;

view1.backgroundColor = [UIColor greenColor];

[superview addSubview:view1];

UIEdgeInsets padding = UIEdgeInsetsMake(74, 10, 10, 10);

[superview addConstraints:@[

//view1 constraints

[NSLayoutConstraint constraintWithItem:view1

attribute:NSLayoutAttributeTop

relatedBy:NSLayoutRelationEqual

toItem:superview

attribute:NSLayoutAttributeTop

multiplier:1.0

constant:padding.top],

[NSLayoutConstraint constraintWithItem:view1

attribute:NSLayoutAttributeLeft

relatedBy:NSLayoutRelationEqual

toItem:superview

attribute:NSLayoutAttributeLeft

multiplier:1.0

constant:padding.left],

[NSLayoutConstraint constraintWithItem:view1

attribute:NSLayoutAttributeBottom

relatedBy:NSLayoutRelationEqual

toItem:superview

attribute:NSLayoutAttributeBottom

multiplier:1.0

constant:-padding.bottom],

[NSLayoutConstraint constraintWithItem:view1

attribute:NSLayoutAttributeRight

relatedBy:NSLayoutRelationEqual

toItem:superview

attribute:NSLayoutAttributeRight

multiplier:1

constant:-padding.right],

]];

}

运行效果如下:

这就是我们用系统的NSLayoutConstraint写的一个view,然后将这个view加载到根view中。现在我们用Masonry来实现和上边一样的效果:

第一步、导入类库

#import "Masonry.h"

然后修改代码如下:

- (void)viewDidLoad {

[super viewDidLoad];

self.title  = @"Basic View";

UIView *superview = self.view;

UIView *view1 = [[UIView alloc] init];

view1.translatesAutoresizingMaskIntoConstraints = NO;

view1.backgroundColor = [UIColor greenColor];

[superview addSubview:view1];

UIEdgeInsets padding = UIEdgeInsetsMake(74, 10, 10, 10);

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(superview.mas_top).offset(padding.top);

make.left.equalTo(superview.mas_left).offset(padding.left);

make.bottom.equalTo(superview.mas_bottom).offset(-padding.bottom);

make.right.equalTo(superview.mas_right).offset(-padding.right);

}];

}

上面的效果和原来用NSLayoutConstraint实现的效果是一样的,所以就不再贴图。

我们可以看到,我们使用的一个mas_makConstrints块来进行约束设置。view1指代的就是要添加约束的view(也可以是button,label等等)。然后make的top,left,bottom,right就相当于view1的上下左右,然后equalTo()括号内的就是相对的view,然后offset是偏移量。

还可以更简单的实现:

- (void)viewDidLoad {

[super viewDidLoad];

self.title  = @"Basic View";

UIView *superview = self.view;

UIView *view1 = [[UIView alloc] init];

view1.translatesAutoresizingMaskIntoConstraints = NO;

view1.backgroundColor = [UIColor greenColor];

[superview addSubview:view1];

UIEdgeInsets padding = UIEdgeInsetsMake(74, 10, 10, 10);

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {

make.edges.equalTo(superview).with.insets(padding);

}];

//    [view1 mas_makeConstraints:^(MASConstraintMaker *make) {

//        make.top.equalTo(superview.mas_top).offset(padding.top);

//        make.left.equalTo(superview.mas_left).offset(padding.left);

//        make.bottom.equalTo(superview.mas_bottom).offset(-padding.bottom);

//        make.right.equalTo(superview.mas_right).offset(-padding.right);

//    }];

}

以上的三种方式都是实现上边图种的效果。

MASViewAttributeNSLayoutAttribute

view.mas_leftNSLayoutAttributeLeft

view.mas_rightNSLayoutAttributeRight

view.mas_topNSLayoutAttributeTop

view.mas_bottomNSLayoutAttributeBottom

view.mas_leadingNSLayoutAttributeLeading

view.mas_trailingNSLayoutAttributeTrailing

view.mas_widthNSLayoutAttributeWidth

view.mas_heightNSLayoutAttributeHeight

view.mas_centerXNSLayoutAttributeCenterX

view.mas_centerYNSLayoutAttributeCenterY

view.mas_baselineNSLayoutAttributeBaseline

以上的属性对应相应的NSLayoutAttribute。

下面就来看它的使用吧。(先上效果图,然后再上代码)

使用一、简单的三个视图的布局

这个时我直接自定义了一个ZGBasicView视图,然后添加到了ViewController中。

关键代码如下:

//

//  ZGBasicView.m

//  MasonryDemo

//

//  Created by zhanggui on 15/10/26.

//  Copyright © 2015年 zhanggui. All rights reserved.

//

#import "ZGBasicView.h"

#import "View+MASShorthandAdditions.h"

@implementation ZGBasicView

/*

// Only override drawRect: if you perform custom drawing.

// An empty implementation adversely affects performance during animation.

- (void)drawRect:(CGRect)rect {

// Drawing code

}

*/

- (id)init {

self = [super init];

if (!self) {

return nil;

}

//        self.translatesAutoresizingMaskIntoConstraints = YES;

//红色视图

UIView *redView = [UIView new];

redView.backgroundColor = [UIColor redColor];

redView.layer.borderColor = [UIColor blackColor].CGColor;

redView.layer.borderWidth = 2;

[self addSubview:redView];

//绿色视图

UIView *greenView = [[UIView alloc] init];

greenView.backgroundColor = [UIColor greenColor];

greenView.layer.borderColor = [UIColor blackColor].CGColor;

greenView.layer.borderWidth = 2;

[self addSubview:greenView];

//蓝色视图

UIView *blueView = [[UIView alloc] init];

blueView.backgroundColor = [UIColor blueColor];

blueView.layer.borderWidth = 2;

blueView.layer.borderColor = [UIColor blackColor].CGColor;

[self addSubview:blueView];

int padding = 10;

UIView *superview = self;

//with is semantic and option

[redView mas_makeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(superview.mas_top).offset(padding); //with with

make.left.equalTo(greenView.mas_right).offset(padding); //without with

make.bottom.equalTo(blueView.mas_top).offset(-padding);

make.right.equalTo(superview.mas_right).offset(-padding);

make.width.equalTo(greenView.mas_width);

make.height.equalTo(@[greenView, blueView]); //can pass array of views

}];

[greenView mas_makeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(superview.mas_top).offset(padding);

make.left.equalTo(superview.mas_left).offset(padding);

make.bottom.equalTo(blueView.mas_top).offset(-padding);

make.right.equalTo(redView.mas_left).offset(-padding);

make.width.equalTo(redView.mas_width);

make.height.equalTo(redView.mas_height);

//            make.height.equalTo(blueView.mas_height);

}];

[blueView mas_makeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(greenView.mas_bottom).offset(padding);

make.left.equalTo(superview.mas_left).offset(padding);

make.bottom.equalTo(superview.mas_bottom).offset(-padding);

make.right.equalTo(superview.mas_right).offset(-padding);

make.height.equalTo(greenView.mas_height); //can pass array of attributes

}];

return self;

}

@end

三个视图之间的关系。

场景二、更新视图

效果图如下:

实现代码如下:(这里也是自定义了一个View,然后将这个view加入到了根视图中)

//

//  UpdateConstraintsView.m

//  MasonryDemo

//

//  Created by zhanggui on 15/10/26.

//  Copyright © 2015年 zhanggui. All rights reserved.

//

#import "UpdateConstraintsView.h"

#import "Masonry.h"

@interface UpdateConstraintsView ()

@property (nonatomic,strong)UIButton *myButton;

@property (nonatomic,assign)CGSize buttonSize;

@end

@implementation UpdateConstraintsView

- (id)init {

self = [super init];

if (self) {

self.myButton = [UIButton buttonWithType:UIButtonTypeSystem];

[self.myButton setTitle:@"更新约束" forState:UIControlStateNormal];

self.myButton.layer.borderColor = [UIColor blackColor].CGColor;

self.myButton.layer.borderWidth = 2;

[self.myButton addTarget:self action:@selector(changeAction:) forControlEvents:UIControlEventTouchUpInside];

[self addSubview:self.myButton];

self.buttonSize = CGSizeMake(100, 100);

}

return self;

}

/**

Returns whether the receiver depends on the constraint-based layout system.

YES if the view must be in a window using constraint-based layout to function properly, NO otherwise.

*/

+ (BOOL)requiresConstraintBasedLayout {

return YES;

}

/**

Updates constraints for the view.

Custom views that set up constraints themselves should do so by overriding this method. When your custom view notes that a change has been made to the view that invalidates one of its constraints, it should immediately remove that constraint, and then call setNeedsUpdateConstraints to note that constraints need to be updated. Before layout is performed, your implementation of updateConstraints will be invoked, allowing you to verify that all necessary constraints for your content are in place at a time when your custom view’s properties are not changing.

You must not invalidate any constraints as part of your constraint update phase. You also must not invoke a layout or drawing phase as part of constraint updating.

Important:Important

Call [super updateConstraints] as the final step in your implementation.

苹果推荐在这个方法里面添加或者更新约束

*/

- (void)updateConstraints {

[self.myButton mas_updateConstraints:^(MASConstraintMaker *make) {

make.center.equalTo(self);

make.width.equalTo(@(self.buttonSize.width)).priorityLow();  //设置优先级以及width

make.height.equalTo(@(self.buttonSize.height)).priorityLow();

//设置myButton的大小小于等于自身view的大小

make.width.lessThanOrEqualTo(self);

make.height.lessThanOrEqualTo(self);

}];

[super updateConstraints];

}

- (void)changeAction:(UIButton *)button {

self.buttonSize = CGSizeMake(self.buttonSize.width*1.2, self.buttonSize.height*1.2);

//告诉约束他们需要更新

[self setNeedsUpdateConstraints];

//update constraints now

[self updateConstraintsIfNeeded];

//设置更新大小动画

[UIView animateWithDuration:0.5 animations:^{

/**

Lays out the subviews immediately.

Use this method to force the layout of subviews before drawing. Using the view that receives the message as the root view, this method lays out the view subtree starting at the root.

*/

[self layoutIfNeeded];

}];

}

@end

这里主要使用了mas_updateConstraints:方法

场景三、让约束复原

实现代码如下:

//

//  ReBackConstraintsView.m

//  MasonryDemo

//可以恢复原来的约束

//  Created by zhanggui on 15/10/26.

//  Copyright © 2015年 zhanggui. All rights reserved.

//

#import "ReBackConstraintsView.h"

#import "Masonry.h"

@interface ReBackConstraintsView ()

@property (nonatomic,strong)UIButton *myButton;

@property (nonatomic,assign)BOOL isAtTop;

@end

@implementation ReBackConstraintsView

- (id)init {

self = [super init];

if (self) {

self.myButton = [UIButton buttonWithType:UIButtonTypeSystem];;

[self.myButton setTitle:@"Move Me!" forState:UIControlStateNormal];

self.myButton.layer.borderColor = UIColor.greenColor.CGColor;

self.myButton.layer.borderWidth = 3;

[self.myButton addTarget:self action:@selector(moveAction:) forControlEvents:UIControlEventTouchUpInside];

[self addSubview:self.myButton];

self.isAtTop = YES;

}

return self;

}

+ (BOOL)requiresConstraintBasedLayout {

return YES;

}

- (void)updateConstraints {

[self.myButton mas_remakeConstraints:^(MASConstraintMaker *make) {

make.width.equalTo(@(100));

make.height.equalTo(@(100));

if (self.isAtTop) {

make.left.equalTo(self.mas_left).offset(10);

make.top.equalTo(self.mas_top).offset(10);

}else {

make.bottom.equalTo(self.mas_bottom).offset(-10);

make.right.equalTo(self.mas_right).offset(-10);

}

}];

[super updateConstraints];

}

- (void)moveAction:(UIButton *)myButton {

self.isAtTop = !self.isAtTop;

//告诉约束他们需要更新

[self setNeedsUpdateConstraints];

//立刻更新视图约束

[self updateConstraintsIfNeeded];

[UIView animateWithDuration:0.3 animations:^{

[self layoutIfNeeded];

}];

}

/*

// Only override drawRect: if you perform custom drawing.

// An empty implementation adversely affects performance during animation.

- (void)drawRect:(CGRect)rect {

// Drawing code

}

*/

@end

这里主要使用了mas_remakeConstraints:方法。

场景四、两个视图的嵌套

实现代码:

//

//  NestConstraintsView.m

//  MasonryDemo

//

//  Created by zhanggui on 15/10/26.

//  Copyright © 2015年 zhanggui. All rights reserved.

//

#import "NestConstraintsView.h"

#import "Masonry.h"

@implementation NestConstraintsView

- (id)init {

self = [super init];

if (self) {

UIView *bigView = [[UIView alloc] init];

bigView.backgroundColor = [UIColor blackColor];

[self addSubview:bigView];

UIView *smallView = [[UIView alloc] init];

smallView.backgroundColor = [UIColor redColor];

[self addSubview:smallView];

[bigView mas_makeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(self).offset(20);

make.left.equalTo(self).offset(20);

make.bottom.equalTo(self).offset(-20);

make.right.equalTo(self).offset(-20);

}];

[smallView mas_makeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(bigView.mas_top).offset(40);

make.left.equalTo(bigView.mas_left).offset(40);

make.bottom.equalTo(bigView.mas_bottom).offset(-40);

make.right.equalTo(bigView.mas_right).offset(-40);

}];

}

return self;

}

@end

这里和第一个场景一样,都是最基本的实现约束的添加,只不过相对参照物不同。

场景五、多个view一起布局(以组为单位布局)

效果:

实现代码:

//

//  GroupButtonView.m

//  MasonryDemo

//

//  Created by zhanggui on 15/10/26.

//  Copyright © 2015年 zhanggui. All rights reserved.

//

#import "GroupButtonView.h"

#import "Masonry.h"

@implementation GroupButtonView

- (instancetype)init {

self  = [super init];

if (self) {

NSArray *strArr = @[@"10",@"20",@"50",@"100",@"200",@"300"];

NSMutableArray *mutableArr = [[NSMutableArray alloc] initWithCapacity:6];

for (int i=0; i<3; i++) {

UIButton *button = [[UIButton alloc] init];

[button setTitle:strArr[i] forState:UIControlStateNormal];

[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

button.layer.borderColor = [UIColor blackColor].CGColor;

[button addTarget:self action:@selector(show:) forControlEvents:UIControlEventTouchUpInside];

button.layer.borderWidth = 2;

[self addSubview:button];

[mutableArr addObject:button];

}

[mutableArr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:20 leadSpacing:20 tailSpacing:20];

[mutableArr mas_makeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(@120);

make.height.equalTo(@75);

}];

/**

*  -----------------------

*/

NSMutableArray *marr = [NSMutableArray new];

for (int i=3; i<6; i++) {

UIButton *button = [[UIButton alloc] init];

[button setTitle:strArr[i] forState:UIControlStateNormal];

[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

button.layer.borderColor = [UIColor blackColor].CGColor;

[button addTarget:self action:@selector(show:) forControlEvents:UIControlEventTouchUpInside];

button.layer.borderWidth = 2;

[self addSubview:button];

[marr addObject:button];

}

[marr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:20 leadSpacing:20 tailSpacing:20];

[marr mas_makeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(@200);

make.height.equalTo(@75);

}];

}

return self;

}

- (void)show:(UIButton *)button

{

NSLog(@"%@",button.titleLabel.text);

}

@end

在这里,我们主要就是用到了mas_distributeViewsAlongAxis:...这个方法,来万曾一组视图的布局。

场景六、自己写的一个简单的登录界面

效果如下:

代码如下:

//

//  ViewController.m

//  MasonryDemo

//

//  Created by zhanggui on 15/10/8.

//  Copyright © 2015年 zhanggui. All rights reserved.

//

#import "ViewController.h"

#import "Masonry.h"

#import "ZGBasicView.h"

#import "UpdateConstraintsView.h"

#import "ReBackConstraintsView.h"

#import "NestConstraintsView.h"

#import "GroupButtonView.h"

#import "LoginView.h"

#import "ArrayView.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

self.title  = @"登录";

[self loginView];

//    [self addArrayView];

}

- (void)loginView {

LoginView *loginView = [[LoginView alloc] init];

self.view = loginView;

//    loginView.frame = self.view.frame;

//    [self.view addSubview:loginView];

}

- (void)addArrayView {

ArrayView *arrView = [[ArrayView alloc] init];

self.view = arrView;

}

- (void)groupButtonView {

GroupButtonView *nestView = [[GroupButtonView alloc] init];

nestView.frame = self.view.frame;

//    self.view = nestView;

[self.view addSubview:nestView];

}

- (void)nestConstraintsView {

NestConstraintsView *nestView = [[NestConstraintsView alloc] init];

self.view = nestView;

}

- (void)reBackConstraints {

ReBackConstraintsView *rebackView = [[ReBackConstraintsView alloc] init];

self.view = rebackView;

}

- (void)updateConstraintsView {

UpdateConstraintsView *updateView = [[UpdateConstraintsView alloc] init];

self.view = updateView;

}

- (void)simpleView {

ZGBasicView *basicView = [[ZGBasicView alloc] init];

//    [self.view addSubview:basicView];

self.view = basicView;

}

- (void)firstSimpleView {

UIView *superview = self.view;

UIView *view1 = [[UIView alloc] init];

view1.translatesAutoresizingMaskIntoConstraints = NO;

view1.backgroundColor = [UIColor greenColor];

[superview addSubview:view1];

UIEdgeInsets padding = UIEdgeInsetsMake(74, 10, 10, 10);

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {

make.edges.equalTo(superview).with.insets(padding);

}];

//    [view1 mas_makeConstraints:^(MASConstraintMaker *make) {

//        make.top.equalTo(superview.mas_top).offset(padding.top);

//        make.left.equalTo(superview.mas_left).offset(padding.left);

//        make.bottom.equalTo(superview.mas_bottom).offset(-padding.bottom);

//        make.right.equalTo(superview.mas_right).offset(-padding.right);

//    }];

}

@end

大家可以简单的看一下,写的比较简单,应该很容易理解的。(横屏的距离上边的高度没有处理太好,将就着看吧)

简单就介绍这么多了。

附:

1、源码下载地址:http://pan.baidu.com/s/1o6083G2

2、Masonry Git地址:https://github.com/SnapKit/Masonry

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

推荐阅读更多精彩内容

  • 一、先做一个比较 使用系统自带的方法 使用 masonry 实现同样效果,代码进行比较: 第一种方法: 第二种方法...
    magic_pill阅读 1,660评论 1 4
  • (一)Masonry介绍 Masonry是一个轻量级的布局框架 拥有自己的描述语法 采用更优雅的链式语法封装自动布...
    木易林1阅读 2,199评论 0 3
  • Masonry是一个轻量级的布局框架,拥有自己的描述语法,采用更优雅的链式语法封装自动布局,简洁明了并具有高可读性...
    3dcc6cf93bb5阅读 1,685评论 0 1
  • iOS_autoLayout_Masonry 概述 Masonry是一个轻量级的布局框架与更好的包装AutoLay...
    指尖的跳动阅读 1,121评论 1 4
  • 这仅仅是个一虚构故事! 红狐领着三个孩子向这座城市唯一的动物生态园区走去。这大过年的,园区还是那样拥挤,排着长长的...
    广羽三妞阅读 238评论 1 1