UIScrollview 与 Autolayout 的那点事
原文 http://www.cocoachina.com/ios/20151221/14757.html
前言
自从写了 介绍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 的那点事的更多相关文章
- 示例详解:UIScrollview 与 Autolayout 的那点事
前言 自从写了介绍Masonry那篇文章以后 就一直有人对UIScrollView的那个例子不是很理解 UIView *container = [UIView new]; [scrollView ad ...
- UIScrollView在AutoLayout下的滚动问题
使用Storyboard编写UI,设置支持AutoLayout. 在其中的一个场景上,添加一个UIScrollView,在对应的代码里增加 - (void)viewDidLoad { [super v ...
- UIScrollView使用autolayout 垂直滚动
转自:http://dadage456.blog.163.com/blog/static/30310744201491141752716 1.创建一个空白的UIViewController .将UIS ...
- UIScrollView的AutoLayout约束
首先UIScrollview包含自身的frame和contentSize二个部分.frame决定其展示给用户的可见区域,contentSize决定其整个内容的大小.如果frame的宽高小于conten ...
- iOS UIScrollView使用Autolayout
最近项目在迭代更新的时候,需要在之前用Autolayout写的界面里添加一个button,添加完这个button后,iPhone5,iPhone4显示不全了.遇到整个问题后很自然就想到了用UIScro ...
- iOS— UIScrollView和 UIPageControl之间的那些事
本代码主要实现在固定的位置滑动图片可以切换. 目录图如下: ViewController.h #import <UIKit/UIKit.h> // 通过宏定义定义宽和高 #define W ...
- Storyboard中使用UIscrollView添加约束的开发总结
第一次在项目中用storyboard做界面,一般的界面直接添加约束非常爽快 然后有个界面有scrollview,添加了约束还总是出错 刚开始使用了 wCompact,hRegular,滑动出现问题,有 ...
- 【原】Masonry+UIScrollView的使用注意事项
[原]Masonry+UIScrollView的使用注意事项 本文转载请注明出处 —— polobymulberry-博客园 1.问题描述 我想实现的使用在一个UIScrollView依次添加三个UI ...
- iOS autoLayout总结
本文转自 http://ruikq.github.io/ios/autolayout/uiscrollview/2015/01/27/iOS-autolayout%E6%80%BB%E7%BB%93. ...
随机推荐
- Linux shell中&,&&,|,||的用法
前言 在玩dvwa的命令注入漏洞的时候,遇到了没有预料到的错误,执行 ping 127.0.0.1 & echo "<?php phpinfo(); ?>" & ...
- Homebrew1.5之后安装PHP和扩展
Homebrew 1.5 宣布放弃 homebrew/php, 转而使用homebrew/core维护, 详见https://brew.sh/2018/01/19/homebrew-1.5.0/ 于是 ...
- Vs2012 编写代码规则
FxCop编写规则 VS2012 下更方便,所需的DLL在: D:\Program Files (x86)\Microsoft Visual Studio 11.0\Team Tools\Static ...
- WPF 自定义 MessageBox (相对完善版 v1.0.0.6)
基于WPF的自定义 MessageBox. 众所周知WPF界面美观.大多数WPF元素都可以简单的修改其样式,从而达到程序的风格统一.可是当你不得不弹出一个消息框通知用户消息时(虽然很不建议在程序中频繁 ...
- python实现将json数据以json格式写入txt文件
json.dumps中indent参数是设置json缩进量的 举例: tmp = { "aaa" : "111", "bbb" : '222 ...
- 利用Cocoapods创建基于SVN的私有库podspec
由于项目年后要进行组件化,考虑到公司内部实现的一些私有组件,不对外公开,而又想在不同项目中使用,该怎么办呢?由于cocoapods有了强大的功能,可以自己创建podspec,更可以设置私有的库.那么利 ...
- Sprint7
进展:根据昨天查到的资料,今天开始编写闹钟部分的代码,主要实现了闹钟添加事件显示时间主界面.
- 实验二 四则运算 完成版 ver.1
package size; import java.awt.EventQueue; import javax.swing.JFrame; import javax.swing.JMenuBar; im ...
- Ubuntu下tensorboard的使用
1. 找到运行程序的事件输出路径 找到路径并进入,例如我的是在路径/home/ly/codes下: 2. 打开tensorboard服务器 在终端输入(--logdir=自己所存的路径): t ...
- STL的集合set
集合: 集合是由元素组成的一个类,其成员可以是一个集合,也可以是一个原子,通常一个元素在一个集合中不能多次出现:由于对实现集合不是很理解,只简单写下已有的STL中的set集合使用: C++中set基本 ...