前言
UIScrollView相信大家都不陌生,图片轮播器和引导页都能找到它的身影。我们常用到的UITableView和UICollectionView之所以能够滚动,也是因为他们都是UIScrollView的子控件。开发中,还有一个地方不得不用到UIScrollView:当我们的界面需要展示的内容比较多,在某个方向上,所有子空间的尺寸加起来大于屏幕的尺寸(特别是在垂直方向上,所有子控件的高度加起来大于屏幕的高度),这就需要用到UIScrollView来展示所有内容。
UIScrollView常见的两种使用方式
1、纯代码
通过代码添加UIScrollView相对来说会遇到的问题比较少,要想UIScrollView能够滚动主要是通过contentSize属性来设置水平和竖直能够滚动的范围。把握:contentSize的宽(高)必须大于UIScrollView的frame的宽(高),UIScrollView才能在相应方向上滚动这一点基本就OK了。
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor purpleColor];
UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, 300)];
[self.view addSubview:scrollView];
scrollView.contentSize = CGSizeMake( [UIScreen mainScreen].bounds.size.width * 3, 200);
for (int i = 0; i < 3; i++) {
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"Snip20170104_%d",i+1]]];
imageView.frame = CGRectMake(i* [UIScreen mainScreen].bounds.size.width, 0, [UIScreen mainScreen].bounds.size.width, 200);
[scrollView addSubview:imageView];
}
}
2. 通过Xib或者StoryBoard (给出的约束下,控件有且唯一存在)
由于Xib或者StoryBoard 是类似的,所以这里也就只讨论Xib了。使用Xib开发不仅可以大大提高开发效率,而且可以提供可视化的界面,有利益开发者开发界面时高效的布局子控件。通过Xib添加控件,想要不报红,一般:系统默认给出宽高的控件,eg. UISegementController、UISwitch 和UISlider等,至少需要添加两个额外的约束;UILabel和UIButton同样也只需添加两个除宽高以外的约束;没有给出默认宽高的控件,eg. UIView、UIImageView和UITableView等则至少需要添加4个约束;总得来说,要想不报红,就得让系统知道你所添加的控件它应该放在什么位置怎么放。一般需要4个约束这一点,从我们设置frame就可以看得出来。frame的x和y可以确定该控件的左上角点在其父控件的位置,那么也就决定了在父控件中从哪一点开始布局该子控件,宽高又决定了布局时该控件在x轴和y轴方向上需要占用多少的距离,通过这四个约束有且唯一存在一个控件,这样系统就知道怎么放我么的控件了。
xib 布局scrollView过程分析
1. 控制器的view添加一个scrollView,设置左右上下距控制器的view都为0,因为能够唯一的确定该scrollView, 所以不会报红。
2. 给scrollView添加一个新的view,并且添加4个约束。如果,该view是添加到一个普通的view上,我们知道不会报红,但是添加到上面的scrollView上却报红。
3. 给该view添加高度160,高度方向上不再报红,宽度上依然报红。
4. 继续添加一个宽度约束,该view终于正常了。
5. 运行结果。该view水平和垂直方向上都不能移动。
6. 修改高度约束,让高度为800(大于屏幕高度),垂直方向上可以滚动了。如果设置宽度大于屏幕的宽度,你会发现在水平方向上也能滚动了。
小结:
通过上面又臭又长的过程,笔者无非也就是想表达两点:
1、xib中,scrollView上的子控件,需要的约束不止4条;
2、要想scrollview不报红,必须让scrollView知道在水平和垂直方向上,放下自己的所有子控件所需的最大宽和高,这样scrollview才知道,自己在水平方向和垂直方向上能否滚动。
至于上述过程中需要设置宽高必须大于屏幕的宽高才可以滚动这一点,联想到纯代码中设置contentSize的要求就能明白了(如果在水平或者垂直方向上,需要展示的所有内容一屏幕就能装下,那自然也就不需要滚动了)。
看到这里,有人可能会说,其实就是要求scrollView子控件的约束至少为6个就OK了,因为网上确实有人这么说过,我上面的例子中,添加的view确实也是6个约束。下面我们再来看个例子。
1、给scrollview添加三个view,分别设置每个view的上下左右距离最近view的距离为0,这样三个view都具有了4个约束,经过上面的分析,这样做肯定是要报红的,因为scrollview不知道自己的子控件在水平和垂直方向上到底占用多少距离。
2、为此,再给三个view都添加高度约束250,发现高度方向上不在报红,因为此时已经能够确定scrollView在垂直方向上需要展示内容的高度加起来为750,大于屏幕高度,垂直方向上可以滚动。
3、给第一个view设置宽度为375,下面两个不设置宽度约束,发现宽度方向上也不在报红,运行程序发现,垂直方向上可以滚动,水平方向上不可以。
小结:
通过上面的描述发现,第一个view有6个约束,其余两个只有5个约束,所以scrollview的子控件需要6个约束并非完全正确。个人觉得,scrollview的子控件添加约束的关键还是在于,让scrollview不仅知道怎么放置所有子控件,还要让其知道自己在水平和垂直方向上是否可以滚动。
注:上述例子中为什么只需要设置第一个view的宽度?因为:通过开始的4条约束,已经能确定下面两个view和第一个的宽度是相同的。这样设置了第一个View的宽度,scrollview就已经知道了自己所有子控件在水平方向上需要的最大宽度。