前言

自从写了介绍Masonry那篇文章以后 就一直有人对UIScrollView的那个例子不是很理解

UIView *container = [UIView new];
[scrollView addSubview:container];
[container mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(scrollView);
    make.width.equalTo(scrollView);
}];
  • 为什么要用一个container包含其他subview?

  • 为什么指定了edges 还要指定width? 不是多此一举吗?

那么今天我就按照我的理解来说明一下这个问题

梳理

直入主题 要解释之前的问题 最重要的一个概念就是

UIScrollView依靠与其subviews之间的约束来确定ContentSize的大小

换成代码 是这个样子

[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(v1.mas_left);
    make.right.equalTo(v1.mas_right);
    make.top.equalTo(v1.mas_top);
    make.bottom.equalTo(v1.mas_bottom);
}];

这是因为UIScrollView是个非常特殊的view UIScrollView与其subview之间相对位置的约束 并不会直接用于frame的计算 而是会转化为对ContentSize的计算

换句话说 当UIScrollView知道了上下左右的约束分别指向subview什么位置之后 只要subview的位置固定下来了 ContentSize的大小就确定下来了

下面来个简单的例子 强烈建议配合demo来理解下面的例子(demo的链接在文尾)

请点击->在线演示 (为了方便理解 我将ContentSize用红线框了出来 另外为了查看ContentSize 我把UIScrollView的clipTobounds关闭了 可以通过左上角的开关来切换实际的效果)

示例1

[v1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(scrollView);
    make.width.equalTo(scrollView);
    make.height.equalTo(scrollView).multipliedBy(1.5);
}];

效果

这里我建立了一个宽等于scrollview 高等于scrollview高度1.5倍的view 然后scrollview成功的计算出了ContentSize

关键就在于

make.edges.equalTo(scrollView);

这句话其实等同与之前我提到的

[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(v1.mas_left);
    make.right.equalTo(v1.mas_right);
    make.top.equalTo(v1.mas_top);
    make.bottom.equalTo(v1.mas_bottom);
}];

scrollview因为上面的约束 会以v1的大小来计算ContentSize

示例2

如果尝试改变v1的大小 会怎么样呢?

[v1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(scrollView);
    
    make.size.equalTo(scrollView).sizeOffset(CGSizeMake(80, 80));
}];

效果

能看到 当我仅改变v1的大小 而不变其他的东西的情况下 scrollview的ContentSize也是随着v1的大小变化而变化的

示例3

接下来示例就会稍微复杂点 如果同时有两个view 会如何呢?

[v1 mas_makeConstraints:^(MASConstraintMaker *make) {
    
    make.left.top.right.equalTo(scrollView).insets(UIEdgeInsetsMake(10, 10, 0, 10));
    
    make.width.equalTo(scrollView).multipliedBy(1.1);
    make.bottom.equalTo(v2.mas_top).offset(-50);
    make.height.equalTo(@200);
}];
[v2 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.bottom.equalTo(scrollView);
    
    make.left.right.equalTo(v1).insets(UIEdgeInsetsMake(0, 50, 0, 50));
    make.height.equalTo(@250);
}];

效果

这个例子中 scrollview的四个方向的约束并没有放在同一个subview上 而是分别指向了两个view 所以scrollview的ContentSize会根据两个view之间的约束来确定

示例4

如果将四个方向的约束分别放到四个不同的view上面 会怎么样呢?

CGSize size = CGSizeMake(200, 200);
[v1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerY.equalTo(scrollView.mas_top);
    
    make.size.mas_equalTo(size);
}];
[v2 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerX.equalTo(scrollView.mas_left);
    
    make.size.mas_equalTo(size);
    make.right.equalTo(v1.mas_left);
    make.top.equalTo(v1.mas_bottom);
}];
[v3 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerX.equalTo(scrollView.mas_right);
    
    make.size.mas_equalTo(size);
    make.left.equalTo(v1.mas_right);
    make.top.equalTo(v1.mas_bottom);
}];
[v4 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerY.equalTo(scrollView.mas_bottom);
    
    make.size.mas_equalTo(size);
    make.left.equalTo(v1.mas_left);
    make.top.equalTo(v2.mas_bottom);
}];

效果

将四个方向的约束分别指向四个view的中心点 我们也能得到正确的ContentSize

如果你看懂了示例4的代码与效果 相信你对这个问题的所有疑惑都应该已经解除了

那么再回到最开始那个问题

make.edges.equalTo(scrollView);
make.width.equalTo(scrollView);

一般情况下我们使用UIScrollView来进行autolayout布局 都是为了实现类似Android中的线性布局(有很多杂的非重复性的subview 如果使用UITableView和UICollectionView太麻烦) 这时直接使用UIScrollView就会很灵活

那么

如果我们需要竖向的滑动 就把width设为和scrollview相同

如果需要横向的滑动 就把height设为和scrollview相同

就是这么简单

小结

源码和Demo请点这里

前不久@nixzhu也写了一篇关于UIScrollView的文章 然后我在微博上回复说使用一个单一的containerView占满全部,然后把所有的subview添加到containerView中” 不过nixzh 表示他是极力避免这样的 但是后在这个问题上 我是极力推荐这样使用的

就如同示例1和示例2一样 如果你需要添加subview 你只要简单的添加到v1上 并添加与v1的约束 就可以获得正确的ContentSize了

如果不这样做 就类似示例3和示例4 这些边界约束都需要一个一个的设置 这其实是没有必要的

使用单一的containerView其实是这个问题上的最佳实践

示例详解:UIScrollview 与 Autolayout 的那点事的更多相关文章

  1. jquery移除、绑定、触发元素事件使用示例详解

    这篇文章主要介绍了jquery移除.绑定.触发元素事件使用示例详解,需要的朋友可以参考下. unbind(type [,data]) //data是要移除的函数 $('#btn').unbind(&q ...

  2. gcc与g++的编译链接的示例详解

    一.编译方式的示例详解 1. 编译C代码 代码如下:main.c /*!  ************************************************************** ...

  3. 史上最易懂——ReactNative分组列表SectionList使用详情及示例详解

    React Native系列 <逻辑性最强的React Native环境搭建与调试> <ReactNative开发工具有这一篇足矣> <解决React Native un ...

  4. Spring Boot 2.x 快速入门(下)HelloWorld示例详解

    上篇 Spring Boot 2.x 快速入门(上)HelloWorld示例 进行了Sprint Boot的快速入门,以实际的示例代码来练手,总比光看书要强很多嘛,最好的就是边看.边写.边记.边展示. ...

  5. VS2010 Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)

    步骤如下: 1. Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)" title="VS2010 Chart控件(一)Chart控件在ASP.NE ...

  6. socket编程的同步、异步与阻塞、非阻塞示例详解

     socket编程的同步.异步与阻塞.非阻塞示例详解之一  分类: 架构设计与优化 简介图 1. 基本 Linux I/O 模型的简单矩阵 每个 I/O 模型都有自己的使用模式,它们对于特定的应用程序 ...

  7. String.format()【示例详解】

    String.format()[示例详解] 整理者:Vashon 前言: String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,为了不止步于简单调用 String.fo ...

  8. SpringBoot与PageHelper的整合示例详解

    SpringBoot与PageHelper的整合示例详解 1.PageHelper简介 PageHelper官网地址: https://pagehelper.github.io/ 摘要: com.gi ...

  9. python中的tcp示例详解

    python中的tcp示例详解  目录 TCP简介 TCP介绍 TCP特点 TCP与UDP的不同点 udp通信模型 tcp客户端 tcp服务器 tcp注意点   TCP简介   TCP介绍 TCP协议 ...

  10. 在java poi导入Excel通用工具类示例详解

    转: 在java poi导入Excel通用工具类示例详解 更新时间:2017年09月10日 14:21:36   作者:daochuwenziyao   我要评论   这篇文章主要给大家介绍了关于在j ...

随机推荐

  1. asp.net MVC4的执行流程

    MVC在底层和传统的asp.net是一致的,在底层之上,相关流程如下: 1)Global.asax里,MvcApplication对象的Application_Start()事件中,调用 RouteC ...

  2. 【C#】第2章学习要点

    分类:C#.VS2015 创建日期:2016-06-15 教材:(十二五国家级规划教材)<C#程序设计及应用教程>(第3版) 一.本章要点 C#数据类型分两大类:值类型.引用类型. 值类型 ...

  3. CentOS添加路由表

    CentOS下静态路由修改命令方法一:添加路由route add -net 192.168.0.0/24 gw 192.168.0.1route add -host 192.168.1.1 dev 1 ...

  4. MyEclipse10 中的两种FreeMarker插件的安装与配置

    第一个插件是:                                       freemarker-ide MyEclipce10.0中安装FreeMarker插件,这绝对是最简单的方法 ...

  5. 在腾讯云上面搭建WordPress博客网站

    一.准备工作 我们使用腾讯云服务器来运行WordPress,腾讯云会给新用户七天的产品体验时间还有一些代金券,做为新手尝试成本是比较小的. 腾讯云长期举办 "云+校园" 活动,学生 ...

  6. 【转】Nginx区分PC或手机访问不同网站

    原文链接:http://www.nginx.cn/784.html 近几年来,随着手机和pad的普及,越来越多的用户选择使用移动客户端访问网站,而为了获取更好的用户体验,就需要针对不同的设备显示出最合 ...

  7. 代码验证浏览器是否支持html audio 和video

    <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8&quo ...

  8. PhotoSwipe - 移动开发必备的 iOS 风格相册

    PhotoSwipe 是一个专门针对移动设备的图像画廊,它的灵感来自 iOS 的图片浏览器和谷歌移动端图像. PhotoSwipe 提供您的访客熟悉和直观的界面,使他们能够与您的移动网站上的图像进行交 ...

  9. CSS教程:vlink,alink,link和a:link

    超链接文字的状态可以通过伪类选择符+样式规则来控制. 一组专门的预定义的类称为伪类,主要用来处理超链接的状态.超链接文字的状态可以通过伪类选择符+样式规则来控制.伪类选择符包括: 总: a 表示 超链 ...

  10. 认识基本的mfc控件

    几乎可以在每个windows程序中都看到按钮.复选框.文本框以及下拉列表等等,这些都是控件.而且很多常用的控件已经内置到操作系统当中了,在Visual C++中,这些常用控件已经简答到能用“拖放”这种 ...