UIScrollView和Autolayout

使用Autolayout,不可避免要碰到ScorllView。

根据Apple的文档:UIScrollView And Autolayout,有两种做法:

  • 混合方式
  • 纯Autolayout

我分别写了两个例子说明各自的用法。实现的界面效果很简单。这是竖屏的:

这是横屏的:

混合方式

代码见这里:https://github.com/MarshalW/ScrollViewAndAutolayout/tree/mix

下面说一下步骤。

先创建一个ScrollView,用Autolayout将它设置在RootView中,constraint(约束)是:上下左右设置了边距(pin)。

然后通过outlet将这个ScrollView连接到ViewController中:

1
2
3
4
5
6
7
@interface ViewController ()

@end

@implementation ViewController{
__weak IBOutlet UIScrollView *scrollView;
}

再往后,创建一个xib文件,用来充当ScrollView中的ContentView:

在xib文件中有多个子视图,最上面的视图,约束是:

  • 左、右和上边距
  • 设置视图的高度

后面的视图,约束是:

  • 和前面视图的边距
  • 和前面视图左右对齐
  • 视图高度

下一步,需要将xib加载进来加入到ScrollView中,因为是通过设置Frame的方式加载的(而不是Autolayout),因此被称作混合方式,见代码:

1
2
3
4
5
6
7
8
9
10
11
- (void)viewDidLoad {
[super viewDidLoad];
[self initContentView];
}

-(void)initContentView{
UIView *contentView=[[[NSBundle mainBundle] loadNibNamed:@"ContentView" owner:self options:nil] objectAtIndex:0];
contentView.frame=CGRectMake(0, 0, scrollView.bounds.size.width, contentView.bounds.size.height);
[scrollView addSubview:contentView];
scrollView.contentSize=contentView.bounds.size;
}

纯Autolayout方式

在上面示例基础上,写了个Pure Autolayout示例。

主要区别是:

  • scrollView中的contentView是通过constraints(Autolayout)设置到根视图上的,我这里编程实现的constraints
  • 不需要设置scrollView的contentSize了,系统会根据constraints自己来确定
  • 需要在viewDidLayoutSubviews方法中修正contentView的width constraint,因为在viewDidLoad中设置width等于scrollView的width,但是此时scrollView的width还没有根据constraint更新
  • 还有就是,iOS7中,需要在viewDidLayoutSubviews方法最后调用一次layoutSubviews,否则App崩溃,iOS8没有这个问题。

代码见: https://github.com/MarshalW/ScrollViewAndAutolayout/tree/pure

看源代码就行了,主要是这个:

1
2
3
4
5
6
7
8
-(void)viewDidLayoutSubviews{
NSLog(@"view did layout subviews");
widthConstraint.constant=scrollView.frame.size.width;

//为了兼容iOS7,http://stackoverflow.com/questions/15490140/auto-layout-error
//iOS8下无需这句话
[self.view layoutSubviews];
}

对亏了stackoverflow上的这个,让我节省很多时间。

还有个事情就是,constraints放在何处,我目前的做法是写在viewDidLoad方法中:

  • constraint只加载1次,其他情况下可做constraint值的修改
  • 如果设置在其他地方,比如viewDidAppear或者其他方法,但是它们可能被调用多次,不适合创建constraint
  • 其他地方适合设置constraint的值,比如viewDidLayoutSubviews或者viewDidAppear

我是参考了这个问题的回答:Where should I be setting autolayout constraints when creating views programatically

iOS