iOS第三方 - Masonry

Masonry

1 - 手写代码所经历的关于页面布局的三个时期

① 在 iPhone - iPhone3gs 时代,window 的 size 固定为 320*480,只需要简单计算一下相对位置就好了

② 在 iPhone4 - iPhone4s 时代,苹果推出了 retina 屏,但是给了码农们非常大的福利:window 的 size 不变

③ 在 iPhone5 - iPhone5s 时代,window 的 size 变成 320*568,这时 autoresizingMask 派上了用场(为啥这时候不用 Autolayout ?因为还要支持 iOS 5 )

④ 在 iPhone6 + 时代,window 的 width 也发生了变化(相对 5/5s 的屏幕比例没有变化) 终于是时候抛弃 autoresizingMask 改用 autolayout 了

⑤ 如何快速的上手 autolayout 呢? 当年 iOS 6 推出的同时新增了 autolayout 的特性 , 但使用起来过于的繁琐和啰嗦,直到 iPhone 6 发布之后,使用 autolayout 就势在必行。此时第三方库 Masonry 就排上了用场:没有学习任何的官方文档或者其它的关于 autolayout 的知识,便可自由进行页面布局

2 - 使用 iOS 原生的框架代码来进行 autoLayout 布局,无论是代码量还是结构的清晰度,表现力度难免差强人意,而在 storyBoard 中只需要几条线就可以搞定的事情,用代码却要写冗余的一大堆,并且有的时候,storyBoard 并不能解决所有问题

3 - Masonry 是一个轻量级布局框架,拥有自身的描述性语法,它采用优雅的链式语法对自动布局进行了封装,同时支持 iOS 和 Mac OS XMasonry。Masonry 中的一系列属性与 NSLayoutAttribute 的对应关系如下

leading 与 left、trailing、right 在正常情况下是等价的,但是当一些布局是从右至左时(比如阿拉伯文) 则会对调(基本可以不理不用),只管用 left 和 right 即可

4 - 三个方法让你玩转 Masonry

① 添加约束:创建一个 label,将其尺寸设置为 50*50,显示在屏幕中间(在添加约束前,受约束的视图必须添加到父视图上

复制代码
 1 #import "Masonry.h"// 头文件
 2 #import "ViewController.h"
 3 @implementation ViewController
 4 
 5 - (void)viewDidLoad {
 6     [super viewDidLoad];
 7     self.view.backgroundColor = [UIColor whiteColor];
 8 
 9     // 受约束视图
10     UILabel *label = [[UILabel alloc]init];
11     label.backgroundColor = [UIColor redColor];
12     // 必须有父视图
13     [self.view addSubview:label];
14     // 这个方法用于在最开始时为控件设置约束
15     [label mas_makeConstraints:^(MASConstraintMaker *make) {
16         make.center.equalTo(self.view);
17         make.height.equalTo(@50);// equalTo 仅支持 NSNumber | CGPoint | CGSize | UIEdgeInsets 数据类型
18         make.width.equalTo(@50); // 等同于 make.size.mas_equalTo(CGSizeMake(50,50));
19     }];
20 }
21 
22 @end
复制代码

equalTo 和 mas_equalTo的区别 ? 其实 mas_equalTo 是一个 MACRO,可以看到 mas_equalTo 只是对其参数进行了一个 BOX 操作(装箱)

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

② 更新约束:当需要配合布局改变或者动画效果的时候,可能需要将已经添加的约束进行更新,更新约束的作用在于更新某些添加的约束,并不会移除掉原有的约束

复制代码
 1 #define MAS_SHORTHAND
 2 // 该宏可在 masonry 进行约束时,省略 mas_ 的使用,
 3 // 注意不要定义到 masonry 头文件的下方
 4 #define MAS_SHORTHAND_GLOBALS
 5 #import "Masonry.h"
 6 #import "ViewController.h"
 7 @implementation ViewController
 8 
 9 - (void)viewDidLoad {
10     [super viewDidLoad];
11     self.view.backgroundColor = [UIColor whiteColor];
12 
13     UILabel * label = [[UILabel alloc]init];
14     label.backgroundColor = [UIColor redColor];
15     [self.view addSubview:label];//
16 
17     // 起始尺寸 50 * 50
18     [label mas_makeConstraints:^(MASConstraintMaker *make) {
19         make.center.equalTo(self.view);
20         make.height.equalTo(@50);
21         make.width.equalTo(@50);
22     }];
23 
24 
25     // 更新布局:mas_updateConstraints
26     [label updateConstraints:^(MASConstraintMaker *make) {
27 
28         make.height.equalTo(300);// equalTo 此时相当于 mas_equalTo。因宏的原因,mas_equalTo 支持的数据类型也更加广泛
29         make.width.equalTo(@100);
30     }];
31 }
32 
33 
34 @end
复制代码

③ 重设约束:它会清除之前所有的约束,只保留重设的约束

复制代码
 1 #define MAS_SHORTHAND
 2 #define MAS_SHORTHAND_GLOBALS
 3 #import "Masonry.h"
 4 #import "ViewController.h"
 5 @implementation ViewController
 6 
 7 - (void)viewDidLoad {
 8     [super viewDidLoad];
 9     self.view.backgroundColor = [UIColor whiteColor];
10 
11     UILabel * label = [[UILabel alloc]init];
12     label.backgroundColor = [UIColor redColor];
13     [self.view addSubview:label];//
14 
15     // 起始约束
16     [label mas_makeConstraints:^(MASConstraintMaker *make) {
17         make.center.equalTo(self.view);
18         make.height.equalTo(@50);
19         make.width.equalTo(@50);
20     }];
21 
22     // 重设约束
23     [label remakeConstraints:^(MASConstraintMaker *make) {
24 
25         make.left.equalTo(self.view.mas_left).offset(10);
26         make.top.equalTo(self.view).offset(100);// 此时 self.view 默认为 self.view.top
27         make.height.equalTo(@200);
28         make.width.equalTo(@350);
29     }];
30 }
31 
32 
33 @end 
复制代码

运行效果:起始位置 | 重设约束

         

③ 边距

复制代码
 1 #define MAS_SHORTHAND
 2 #define MAS_SHORTHAND_GLOBALS
 3 #import "Masonry.h"
 4 #import "ViewController.h"
 5 @implementation ViewController
 6 
 7 - (void)viewDidLoad {
 8     [super viewDidLoad];
 9     self.view.backgroundColor = [UIColor whiteColor];
10     self.navigationController.navigationBar.hidden = YES;
11 
12     UILabel * label = [[UILabel alloc]init];
13     label.backgroundColor = [UIColor redColor];
14     [self.view addSubview:label];
15 
16     // 起始约束 50*50
17     [label mas_makeConstraints:^(MASConstraintMaker *make) {
18         make.center.equalTo(self.view);
19         make.height.equalTo(@50);
20         make.width.equalTo(@50);
21     }];
22 
23 
24     // 边距
25     [label remakeConstraints:^(MASConstraintMaker *make) {
26 
27 //        // 方式一:边距均 30 个点
28 //        make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(30, 30, 30, 30));
29         
30 
31 //        // 方式二:具体设置
32 //        make.top.equalTo(self.view).with.offset(30);
33 //        make.left.equalTo(self.view).with.offset(30);
34 //        // 计算的 bottom 需要小于父视图的底部高度,所以这里使用负数 -30
35 //        make.bottom.equalTo(self.view).with.offset(-30);
36 //        make.right.equalTo(self.view).with.offset(-30);
37 
38         // 方式三:约束要和 UIEdgeInsetsMake 参数表达相一致:上左下右
39         make.top.left.bottom.and.right.equalTo(self.view).with.insets(UIEdgeInsetsMake(30, 30, 30, 30));
40     }];
41 }
42 
43 @end
复制代码

运行效果:起始位置 | 边距

       

这里有意思的地方是 and 和 with 其实这两个函数什么事情都没做,但是用在这种链式语法中就非常的巧妙和易懂

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

5 - 其他示例

① 让两个高度为 150 的 UI 垂直居中且等宽、等间隔排列,间隔为 10

复制代码
 1 #define MAS_SHORTHAND
 2 #define MAS_SHORTHAND_GLOBALS
 3 #import "Masonry.h"
 4 #import "ViewController.h"
 5 @implementation ViewController
 6 
 7 - (void)viewDidLoad {
 8     [super viewDidLoad];
 9     self.view.backgroundColor = [UIColor whiteColor];
10 
11     UILabel *label1 = [[UILabel alloc] init];
12     label1.backgroundColor = [UIColor redColor];
13     [self.view addSubview:label1];
14 
15     UILabel *label2 = [[UILabel alloc] init];
16     label2.backgroundColor = [UIColor grayColor];
17     [self.view addSubview:label2];
18 
19 
20     [label1 makeConstraints:^(MASConstraintMaker *make) {
21 
22         make.height.equalTo(150);
23         make.centerY.equalTo(self.view.centerY);
24         make.left.equalTo(self.view.left).offset(10);
25         make.right.equalTo(label2.left).offset(-10);
26         // 关键点
27         make.width.equalTo(label2.width);
28 
29     }];
30 
31 
32     [label2 makeConstraints:^(MASConstraintMaker *make) {
33 
34         make.height.equalTo(label1.height);
35         make.centerY.equalTo(label1.centerY);
36         make.right.equalTo(self.view.right).offset(-10);
37         make.left.equalTo(label1.right).offset(10);
38         // 关键点 关键点 关键点 重要的事情说三遍!
39         make.width.equalTo(label1.width);
40 
41     }];
42 }
43 
44 @end
复制代码

运行效果:在两个 UI 之间互相设置的约束,可以看到它们的宽度在约束下可自动被计算出来

② 在 UIScrollView 中顺序排列一些 view 并自动计算 contentSize

复制代码
 1  #import "Masonry.h"
 2  #import "ViewController.h"
 3  @implementation ViewController
 4 
 5 - (void)viewDidLoad {
 6     [super viewDidLoad];
 7     self.view.backgroundColor = [UIColor whiteColor];
 8     self.navigationController.navigationBar.hidden = YES;
 9 
10     // UIScrollView
11     UIScrollView *scrollView = [UIScrollView new];
12     [self.view addSubview:scrollView];
13     [scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
14         
15         make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(20,5,5,5));
16     }];
17     
18     // UIView
19     UIView *container = [UIView new];
20     [scrollView addSubview:container];
21     [container mas_makeConstraints:^(MASConstraintMaker *make) {
22 
23         make.edges.equalTo(scrollView);// 视图滚动关键点 ①:边距设置后,UIScrollView 的 contentSize 自行填充
24         make.width.equalTo(scrollView);
25     }];
26 
27 
28 
29     // 约定遍历 UIView 个数
30     int count = 8;
31     UIView *lastView = nil;
32     for ( int i = 1 ; i <= count ; i++ ){
33 
34         UIView *subv = [UIView new];
35         [container addSubview:subv];
36         subv.backgroundColor = [UIColor colorWithHue:( arc4random() % 256 / 256.0 )
37                                           saturation:( arc4random() % 128 / 256.0 ) + 0.5
38                                           brightness:( arc4random() % 128 / 256.0 ) + 0.5
39                                                alpha:1];
40 
41         // 约束
42         [subv mas_makeConstraints:^(MASConstraintMaker *make) {
43 
44             make.left.and.right.equalTo(container);
45             make.height.mas_equalTo(20*i);
46 
47             if (lastView){
48                 make.top.mas_equalTo(lastView.mas_bottom);
49             }else{
50                 make.top.mas_equalTo(container.mas_top);
51             }
52         }];
53 
54         lastView = subv;
55     }
56 
57 
58     [container mas_makeConstraints:^(MASConstraintMaker *make) {
59         // 视图滚动关键点 ②:移除此约束后,UIScrollView 将不会滚动
60         make.bottom.equalTo(lastView.mas_bottom);
61     }];
62 }
63 
64 @end
复制代码

运行效果:关键就在于 container 这个 view 起到了一个中间层的作用,它能够自动计算 UIScrollView 的 contentSize

链接:Masonry

https://pan.baidu.com/s/1PLfA5W3F73Gjt-RS_agXjg

qwf5

posted on   低头捡石頭  阅读(62)  评论(0编辑  收藏  举报

编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示