YongSir

专业程序员伪装者

scrollView的一些经验(二)--自动布局的正确姿势

利用storyBoard尝试自动布局ScrollView

实际测试如下:

1 scrollView + imageView(Sizefit)


失败!

2 imageView修改:只有leading和TopSpace,然后再代码中添加打印:

1
2
[self.view layoutIfNeeded]; // 此行之前的layout被计算
NSLog(@"设置了imageView后 %@", self.scrollView);

失败!again

原因分析:通过打印可看出,上述两种方法都无法给出contentSize

1
2
2015-03-11 11:27:32.577 ScrollTagDemo[2393:259138] 只是设置了scrollView的约束,<UIScrollView: 0x7aaf1a00; frame = (190 190; 220 220); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x788a1750>; layer = <CALayer: 0x78689bb0>; contentOffset: {0, 0}; contentSize: {0, 0}>
2015-03-11 11:27:32.579 ScrollTagDemo[2393:259138] 设置了imageView后 <UIScrollView: 0x7aaf1a00; frame = (50 130; 220 220); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x788a1750>; layer = <CALayer: 0x78689bb0>; contentOffset: {0, 0}; contentSize: {0, 0}>

3 imageView再修改,先使用代码:

1
2
self.scrollView.contentSize = self.imageView.bounds.size;
NSLog(@"设置了contentSize的frame之后,%@", self.scrollView);

success!

此时的打印contentSize:

1
2015-03-11 11:52:11.289 ScrollTagDemo[2460:266559] 设置了contentSize的frame之后,<UIScrollView: 0x7b885c00; frame = (190 190; 220 220); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7b06a2e0>; layer = <CALayer: 0x7b064680>; contentOffset: {0, 0}; contentSize: {759, 966}>

所以原因的确是contentSize的问题,这种方式就是官方给出的所谓混合解决方式,但在layout中设置frame可是不常见的,在我看来这有悖于layout的实质,可用但值得商榷,那么就继续探索能够使用约束给出contentSize的方法。
再次修改imageView:

失败,again!

按理说,给定img的宽高,就应该有contentSize了,但遗憾的是木有😢

1
2015-03-11 12:01:10.255 ScrollTagDemo[2525:271602] 设置了contentSize的frame之后,<UIScrollView: 0x7ca72600; frame = (190 190; 220 220); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7c1926d0>; layer = <CALayer: 0x7c18cd80>; contentOffset: {0, 0}; contentSize: {0, 0}>

4 imageView再修改,这次在第二次的基础上尝试:

success!it works!

但是对比先前的

仅仅是把Trainling跟Bottom变成了0,0而已,it works!

由此可见:subView的约束是根据contentSize计算而来的,而不是scroll自己!
但是但是,打印的结果仍然是:

1
2015-03-11 12:10:35.446 ScrollTagDemo[2556:281194] 设置了contentSize的frame之后,<UIScrollView: 0x7b075600; frame = (190 190; 220 220); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7aa2a2f0>; layer = <CALayer: 0x7a8795f0>; contentOffset: {0, 0}; contentSize: {0, 0}>

肯定是打印的地方不对,到底在哪儿呢?再试试,通过自定义view,猜测是laySubViews,重写之后结果验证如下:

1
2
3
4
5
6
7
8
2015-03-11 13:49:47.407 ScrollTagDemo[2846:353070] 设置了imageView后 <UIScrollView: 0x7bbaf000; frame = (190 190; 220 220); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7c145be0>; layer = <CALayer: 0x7b62da80>; contentOffset: {0, 0}; contentSize: {0, 0}>
2015-03-11 13:49:47.407 ScrollTagDemo[2846:353070] 设置了contentSize的frame之后,<UIScrollView: 0x7bbaf000; frame = (190 190; 220 220); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7c145be0>; layer = <CALayer: 0x7b62da80>; contentOffset: {0, 0}; contentSize: {0, 0}>
2015-03-11 13:49:47.412 ScrollTagDemo[2846:353070] -------------->
2015-03-11 13:49:47.413 ScrollTagDemo[2846:353070] timeOfLayout 1
2015-03-11 13:49:47.413 ScrollTagDemo[2846:353070] scrollView.contentSize:{0, 0}
<!-- 2015-03-11 13:49:47.413 ScrollTagDemo[2846:353070] --------------> -->
2015-03-11 13:49:47.413 ScrollTagDemo[2846:353070] timeOfLayout 2
2015-03-11 13:49:47.413 ScrollTagDemo[2846:353070] scrollView.contentSize:{759, 966}

在整个viewDidLoad中都没有计算contentSize,而是在结束之后由系统去view的 layoutSubviews方法中计算的<在iOS8之前是要自己去加上一句的>!

5 再测试:

imageView再添加约束,让其的w和h 跟 scrollView的w和h 相等

also worked!
打印输出:

1
2
3
4
5
6
7
8
2015-03-11 15:52:42.841 ScrollTagDemo[3154:467930] -------------->
2015-03-11 15:52:42.841 ScrollTagDemo[3154:467930] timeOfLayout 1
2015-03-11 15:52:42.884 ScrollTagDemo[3154:467930] scrollView.frame:{{250, 190}, {100, 220}}
2015-03-11 15:52:42.884 ScrollTagDemo[3154:467930] scrollView.contentSize:{0, 0}
2015-03-11 15:52:42.885 ScrollTagDemo[3154:467930] -------------->
2015-03-11 15:52:42.885 ScrollTagDemo[3154:467930] timeOfLayout 2
2015-03-11 15:52:42.885 ScrollTagDemo[3154:467930] scrollView.frame:{{250, 190}, {100, 220}}
2015-03-11 15:52:42.885 ScrollTagDemo[3154:467930] scrollView.contentSize:{759, 966}

发现根本 scrollView.frame就没有变化,但是这明显与通常理解的矛盾,明明已经相等而数值不同,其实这就是系统针对scrollView做的特殊处理,其实并没有真正去加上这个约束,加的其实是:

finally

这就是scrollView的完整约束!这也就是在官方文档中所提到的“by creating constraints between the view and a view outside the scroll view’s subtree, such as the scroll view’s superview”

将这个所谓相等的约束引用更改,就能结合代码更改contentSize

脑洞:既然结果显示w和h可以设置为“>=”,是否意味着可以自己来设置这样的约束对方,没实验,不过估计即便可以也不会有人去这样设置的👌!……^_^