原文网址:http://tutuge.me/2015/05/23/autolayout-example-with-masonry/

好久没有写Blog了,这段时间有点忙啊=。=
本文举了3个比较有“特点”的Autolayout例子,源于微博上好友的提问,感觉比较有意思,也比较有代表性,就写了出来,分享给大家~
至于为什么用Masonry,那是因为它好用啊!(被问到过有关Masonry的问题,就索性用它来实现吧=。=)。

效果图

Github地址

https://github.com/zekunyan/AutolayoutExampleWithMasonry

关于例子工程结构

实现的时候采用的是用StoryBoard拖拽约束+Masonry手写代码相结合的方式实现。最关键的地方是用Masonry,为了更好地突出重点。其它的无关紧要的空间约束,直接就拖拽了。

关于Autolayout

刚开始学习Autolayout的时候,什么“Leading Edges”、“Horizontal Centers”,好多啊,感觉一下子适应不来,有时候面对一个界面布局上的需求,可能都无从下手。

总的来说,我觉得Autolayout的关键就是“Constraint(约束)”。其实就是以下两点:

  1. 从显式设置frame的属性,到利用约束控制View的大小、位置。
  2. 思考如何布局时,重点从单个的View,到整体所有View之间的相互关系。

既然没有了具体设置View的frame属性,也就是说,系统会在运行时,通过我们设定的“约束”,计算出每个View的frame,再去绘制屏幕内容。

也就是说,我们设置的Constraint,要能体现出View的位置(x、y坐标)大小(宽高)。无论是用IB拖拽约束,还是手写代码,只要从这个角度去思考,很多问题就都能解决。

有关Autolayout的知识,网上有很多,在这里就不详细列出了,但是有个公式倒是可以贴出来:

1
viewA-attribute = viewB-attribute * multiplier + constant

关于Masonry

好用!

Case 1: 并排两个label,宽度由内容决定。父级View宽度不够时,优先显示左边label的内容

遇到这种跟内容压缩、优先级有关的布局,就不得不提Autolayout中的两个重要的属性“Content Compression Resistance”和“Content Hugging”。

Content Compression Resistance = 不许挤我!

对,这个属性说白了就是“不许挤我”=。=
这个属性的优先级(Priority)越高,越不“容易”被压缩。也就是说,当整体的空间装不下所有的View的时候,Content Compression Resistance优先级越高的,显示的内容越完整。

Content Hugging = 抱紧!

这个属性的优先级越高,整个View就要越“抱紧”View里面的内容。也就是View的大小不会随着父级View的扩大而扩大。

分析

根据要求,可以将约束分为两个部分:

  1. 整体空间足够时,两个label的宽度由内容决定,也就是说,label的“Content Hugging”优先级很高,而且没有固定的Width属性。
  2. 整体空间不够时,左边的label更不容易被压缩,也就是“Content Compression Resistance”优先级更高。

重点:

  1. label不设置具体的宽度(width)属性,宽度由内容决定。
  2. 显示的优先级由“Content Compression Resistance”属性的高低决定。

约束示例图

关键代码

关键的代码如下:(label1是左边的label,label2是右边的)

设置位置

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
// label1: 位于左上角
[_label1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(_contentView1.mas_top).with.offset(5);
make.left.equalTo(_contentView1.mas_left).with.offset(2); // 40高度
make.height.equalTo(@40);
}]; // label2: 位于右上角
[_label2 mas_makeConstraints:^(MASConstraintMaker *make) {
//左边贴着label1,间隔2
make.left.equalTo(_label1.mas_right).with.offset(2); //上边贴着父view,间隔5
make.top.equalTo(_contentView1.mas_top).with.offset(5); //右边的间隔保持大于等于2,注意是lessThanOrEqual
//这里的“lessThanOrEqualTo”放在从左往右的X轴上考虑会更好理解。
//即:label2的右边界的X坐标值“小于等于”containView的右边界的X坐标值。
make.right.lessThanOrEqualTo(_contentView1.mas_right).with.offset(-2); //只设置高度40
make.height.equalTo(@40);
}];

设置内容约束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//设置label1的content hugging 为1000
[_label1 setContentHuggingPriority:UILayoutPriorityRequired
forAxis:UILayoutConstraintAxisHorizontal]; //设置label1的content compression 为1000
[_label1 setContentCompressionResistancePriority:UILayoutPriorityRequired
forAxis:UILayoutConstraintAxisHorizontal]; //设置右边的label2的content hugging 为1000
[_label2 setContentHuggingPriority:UILayoutPriorityRequired
forAxis:UILayoutConstraintAxisHorizontal]; //设置右边的label2的content compression 为250
[_label2 setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisHorizontal];

小节

灵活运用“Content Compression Resistance”和“Content Hugging”属性。

Case 2: 四个ImageView整体居中,可以任意显示、隐藏

先看看示例的截图:

下面的四个Switch控件分别控制上面对应位置的图片是否显示。

分析

  1. 首先就是整体居中,为了实现这个,最简单的办法就是将四个图片“装进”一个容器View里面,然后让这个容器View在整个页面中居中即可。这样就不用控制每个图片的居中效果了。
  2. 然后就是显示与隐藏。在这里我直接控制图片ImageView的宽度,宽度为0的时候不就“隐藏”了吗。

约束示例图

解释

之所以这么设置,主要目的有以下几点:

  1. 尽量减少无效的约束,保证约束不多也不少。
  2. 内部的每个imageView约束其实都只有四个:left、centerY、width和height,这样有个好处,就是可以在循环里面依次添加约束,大大减少代码量。
  3. 最右边的imageView还要单独设置跟容器View的右边约束,是为了不用设置容器View的width,保证容器View是刚好包含内部的View的,这样整体才是居中的。

关键代码

先看看最外层容器View的代码:

1
2
3
4
5
6
7
8
9
10
//containerView 就是 容器View

[_containerView mas_makeConstraints:^(MASConstraintMaker *make) {
//只设置高度,宽度由子View决定
make.height.equalTo(@(IMAGE_SIZE));
//水平居中
make.centerX.equalTo(self.view.mas_centerX);
//距离父View顶部200点
make.top.equalTo(self.view.mas_top).offset(200);
}];

循环创建每个内部的imageView

1
2
3
4
5
6
//循环创建、添加imageView
for (NSUInteger i = 0; i < 4; i++) {
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:_imageNames[i]]];
[_imageViews addObject:imageView];
[_containerView addSubview:imageView];
}

最后是循环对imageView加上约束: 感谢XVXVXXX的PR:-D

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
//设定大小
CGSize imageViewSize = CGSizeMake(IMAGE_SIZE, IMAGE_SIZE); //分别设置每个imageView的宽高、左边、垂直中心约束,注意约束的对象
//每个View的左边约束和左边的View的右边相等=。=,有点绕口... // 保存循环中的临时结果
__block UIView *lastView = nil;
__block MASConstraint *widthConstraint = nil; NSUInteger arrayCount = _imageViews.count;
[_imageViews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) {
[view mas_makeConstraints:^(MASConstraintMaker *make) {
//宽高固定
widthConstraint = make.width.equalTo(@(imageViewSize.width));
make.height.equalTo(@(imageViewSize.height));
//左边约束
make.left.equalTo(lastView ? lastView.mas_right : view.superview.mas_left);
//垂直中心对齐
make.centerY.equalTo(view.superview.mas_centerY);
//设置最右边的imageView的右边与父view的最右对齐
if (idx == arrayCount - 1) {
make.right.equalTo(view.superview.mas_right);
} [_widthConstraints addObject:widthConstraint];
lastView = view;
}];
}];

控制ImageView显示、隐藏的时候,直接让其宽度等于0就行:

1
2
3
4
5
6
7
8
9
10
- (IBAction)showOrHideImage:(UISwitch *)sender {
NSUInteger index = (NSUInteger) sender.tag;
MASConstraint *width = _widthConstraints[index]; if (sender.on) {
width.equalTo(@(IMAGE_SIZE));
} else {
width.equalTo(@0);
}
}

小节

有时候用个“容器View”管理内部的View,往往会起到事半功倍的效果。而且在组织约束的时候,尽量的将约束统一起来,这样可以用一个函数去设置,减少代码量。

Case 3: 子View的宽度始终是父级View的一半(或者任意百分比)

其实这个很简单=。= 再看看这个公式:

1
viewA-attribute = viewB-attribute * multiplier + constant

这个是Autolayout里面一个约束的不同属性的基本组合关系,替换成宽度的话,就是下面这样:

1
子View的宽度 = 父级View宽度 * 系数 + 常数;

在Masonry里面,其实有个函数“multipliedBy”,就是用来设置multipler属性的(跟原本的NSLayoutConstraint的对应)。

关键代码

如下:

1
2
3
4
5
6
7
8
9
[subView mas_makeConstraints:^(MASConstraintMaker *make) {
//上下左贴边
make.left.equalTo(_containerView.mas_left);
make.top.equalTo(_containerView.mas_top);
make.bottom.equalTo(_containerView.mas_bottom); //宽度为父view的宽度的一半
make.width.equalTo(_containerView.mas_width).multipliedBy(0.5);
}];

接着,只要控制父级View的宽度,子View的宽度就会随着变化了。

小节

multipliedBy在Masonry的Github主页里面没有=。=
所以要养成读头文件的习惯~

总结

有关Autolayout的东西还有好多没有写,什么动画啊、动态修改约束之类的,本文也算是个引子吧,任重而道远~

能看到这的朋友,也算是很有耐心了,哈哈~~

参考

【转】有趣的Autolayout示例-Masonry实现的更多相关文章

  1. AutoLayout框架Masonry使用心得

    AutoLayout框架Masonry使用心得 字数1769 阅读1481 评论1 喜欢17 我们组分享会上分享了页面布局的一些写法,中途提到了AutoLayout,会后我决定将很久前挖的一个坑给填起 ...

  2. iOS开发通过代码方式使用AutoLayout (NSLayoutConstraint + Masonry)

    iOS开发通过代码方式使用AutoLayout (NSLayoutConstraint + Masonry) 随着iPhone6/6+设备的上市,如何让手头上的APP适配多种机型多种屏幕尺寸变得尤为迫 ...

  3. iOS AutoLayout自动布局&Masonry介绍与使用实践

    Masonry介绍与使用实践:快速上手Autolayout http://www.cnblogs.com/xiaofeixiang/p/5127825.html http://www.cocoachi ...

  4. iOS — Autolayout之Masonry解读

    前言 1 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-iphone3gs时 ...

  5. IOS开发通过代码方式使用AutoLayout (NSLayoutConstraint + Masonry) 转载

    http://blog.csdn.net/he_jiabin/article/details/48677911 随着iPhone6/6+设备的上市,如何让手头上的APP适配多种机型多种屏幕尺寸变得尤为 ...

  6. 代码方式使用AutoLayout (NSLayoutConstraint + Masonry)

    随着iPhone6/6+设备的上市,如何让手头上的APP适配多种机型多种屏幕尺寸变得尤为迫切和必要.(包括:iPhone4/4s,iPhone5/5s,iPhone6/6s,iPhone 6p/6ps ...

  7. AutoLayout初战----Masonry与FDTemplateLayoutCell实践

    学iOS也有几个月了.一直都是纯代码开发,菜鸟入门,到今天还处在Frame时代.刚好近期项目在提审.有点时间能够学学传说中的AutoLayout.事实上.就是android的相对布局(Relative ...

  8. 在 AutoLayout 和 Masonry 中使用动画

    动画是 iOS 中非常重要的一部分,它给用户展现出应用灵气的一面. 在动画块中修改 Frame 在原来使用 frame 布局时,在 UIView 的 animate block 中对 view 的布局 ...

  9. Autolayout 第三方开源库

    转载自:http://blog.csdn.net/hmt20130412/article/details/46638625 今天才发现CSDN支持markdown了…还是给出新博客地址:Autolay ...

随机推荐

  1. 1034-IBM技术俱乐部主席竞选

    描述 今天IBM技术俱乐部举行主席竞选,你的任务是统计谁是得票最多的候选人. 输入 输入数据包含多组测试案例. 每组测试案例由N(0<N<1000)开头,N表示投票总数,后续N行每行包含一 ...

  2. java基础知识回顾之javaIO类--java序列化和反序列化

    /** *  * 一:理解序列化反序列化及其应用 * 序列化:把堆内存的对象转化成字节流的过程. * 反序列化:把字节流序列恢复重构成对象的过程. * 对象的序列化的用途:1.把对象的字节序列持久化, ...

  3. POJ1416Shredding Company

    http://poj.org/problem?id=1416 题意 : 要为碎纸机公司开发一种新的碎纸机,这种碎纸机要具有3个特性 :一是粉碎机以一个目标数 t 作为输入,并且粉碎的纸上写有一个数字n ...

  4. POJ1046Color Me Less

    http://poj.org/problem?id=1046 据说这个题是个水题,但我还是WA了好几次,最后才改对了 #include<cstdio> #include<cstrin ...

  5. lintcode :Ugly Numbers 丑数

    题目 丑数 设计一个算法,找出只含素因子3,5,7 的第 k 大的数. 符合条件的数如:3,5,7,9,15...... 样例 如果k=4, 返回 9 挑战 要求时间复杂度为O(nlogn)或者O(n ...

  6. HTML5+开发移动app教程3-mui开发示例

    下面就开始一个简答的例子,以及mui相关内容 mui 官网:http://dcloudio.github.io/mui/ 说明:http://dev.dcloud.net.cn/mui/ui/inde ...

  7. java:定义线程

    Thread是java.lang包的类,默认导入. 进程:操作系统中的程序,多进程即同时运行多个程序.线程:程序中的流,多线程即程序中有多个流同时执行. 一个线程用一个线程对象表示 创建线程的方法: ...

  8. MSSQLServer基础07(事务,存储过程,分页的存储过程,触发器)

    事务 事务:保证多个操作全部成功,否则全部失败,这处机制就是事务 思考:下了个订单,但是在保存详细信息时出错了,这样可以成功吗? 数据库中的事务:代码全都成功则提交,如果有某一条语句失败则回滚,整体失 ...

  9. Intellij IDEA创建javaWeb以及Servlet简单实现

    1.创建web工程 File --> New --> Project...

  10. Android Service实时向Activity传递数据

    演示一个案例,需求如下:在Service组件中创建一个线程,该线程用来生产数值,每隔1秒数值自动加1,然后把更新后的数值在界面上实时显示. 步骤如下:1.新建一个android项目工程,取名为demo ...