关于UIScrollView的约束问题


1
2
3
4
5
6
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的大小

换成代码 是这个样子

1
2
3
4
5
6
[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

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

效果

关于UIScrollView的约束问题_第1张图片

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

关键就在于

1
make.edges.equalTo(scrollView);

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

1
2
3
4
5
6
[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的大小 会怎么样呢?

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

效果

关于UIScrollView的约束问题_第2张图片

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

示例3

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[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);
}];

效果

关于UIScrollView的约束问题_第3张图片

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

示例4

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

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
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);
}];

效果

关于UIScrollView的约束问题_第4张图片

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

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

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

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

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

那么

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

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

就是这么简单


你可能感兴趣的:(关于UIScrollView的约束问题)