示例详解:UIScrollview 与 Autolayout 的那点事
前言
自从写了介绍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 的那点事的更多相关文章
- jquery移除、绑定、触发元素事件使用示例详解
这篇文章主要介绍了jquery移除.绑定.触发元素事件使用示例详解,需要的朋友可以参考下. unbind(type [,data]) //data是要移除的函数 $('#btn').unbind(&q ...
- gcc与g++的编译链接的示例详解
一.编译方式的示例详解 1. 编译C代码 代码如下:main.c /*! ************************************************************** ...
- 史上最易懂——ReactNative分组列表SectionList使用详情及示例详解
React Native系列 <逻辑性最强的React Native环境搭建与调试> <ReactNative开发工具有这一篇足矣> <解决React Native un ...
- Spring Boot 2.x 快速入门(下)HelloWorld示例详解
上篇 Spring Boot 2.x 快速入门(上)HelloWorld示例 进行了Sprint Boot的快速入门,以实际的示例代码来练手,总比光看书要强很多嘛,最好的就是边看.边写.边记.边展示. ...
- VS2010 Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)
步骤如下: 1. Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)" title="VS2010 Chart控件(一)Chart控件在ASP.NE ...
- socket编程的同步、异步与阻塞、非阻塞示例详解
socket编程的同步.异步与阻塞.非阻塞示例详解之一 分类: 架构设计与优化 简介图 1. 基本 Linux I/O 模型的简单矩阵 每个 I/O 模型都有自己的使用模式,它们对于特定的应用程序 ...
- String.format()【示例详解】
String.format()[示例详解] 整理者:Vashon 前言: String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,为了不止步于简单调用 String.fo ...
- SpringBoot与PageHelper的整合示例详解
SpringBoot与PageHelper的整合示例详解 1.PageHelper简介 PageHelper官网地址: https://pagehelper.github.io/ 摘要: com.gi ...
- python中的tcp示例详解
python中的tcp示例详解 目录 TCP简介 TCP介绍 TCP特点 TCP与UDP的不同点 udp通信模型 tcp客户端 tcp服务器 tcp注意点 TCP简介 TCP介绍 TCP协议 ...
- 在java poi导入Excel通用工具类示例详解
转: 在java poi导入Excel通用工具类示例详解 更新时间:2017年09月10日 14:21:36 作者:daochuwenziyao 我要评论 这篇文章主要给大家介绍了关于在j ...
随机推荐
- EasyUI datagrid 行编辑
一.HTML: <div class="info"> <div class="info_tt"> <span class=&quo ...
- 介绍开源的.net通信框架NetworkComms框架 源码分析(二十一 )TCPConnectionListener
原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是 ...
- 为什么我不建议你做APP?
最近迷上了新产品的可行性分析和推演. 有几个朋友也准备跳入创业火坑了,找到我说帮忙做做产品分析和可行性讨论,欣然应允. 我一向厌恶纯凭感觉拍脑袋的方式,所以对于我不了解的行业,都会从行业背景.现状痛点 ...
- 【C#进阶系列】17 委托
委托主要是为了实 现回调函数机制,可以理解为函数指针(唯一不同的在于多了委托链这个概念). 然而用的时候可以这么理解,但是委托的内部机制是比较复杂的. 一个委托的故事 delegate void ra ...
- C语言文件方式输入与输出(最简洁方便实用的一种方式)
freopen("inputfile.txt", "r", stdin); freopen("outputfile.txt", " ...
- jsp页面样例及解析
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
- MySQL高效分页解决方案集(转)
很久以前的一次面试中,被面试官问到这个问题,由于平时用到的分页方法不多,只从索引.分表.使用子查询精准定位偏移以外,没有使用到其它方法. 后来在看其它博客看到了一些不同的方案,也一直没有整理.今天有时 ...
- Linux下安装mongodb详细过程
本次安装mongodb使用yum.repo方式.详细过程请参考,也列出一些安装过程中的错误,欢迎指正. mongodb版本:3.0 先在linux下cd 到 /etc/yum.repos.d/ 新建脚 ...
- Guava学习笔记:Guava cache
缓存,在我们日常开发中是必不可少的一种解决性能问题的方法.简单的说,cache 就是为了提升系统性能而开辟的一块内存空间. 缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用 ...
- Git远程和分支管理
一.远程 Git是分布式版本控制系统,最重要的优点就是远程仓库托管代码.不用自己搭建一个服务器,在github上面注册一个账户就可免费获取远程仓库. 首先需要先在github上面 ...