Update

今天看到了一个更直观更简单的办法

  1. scrollView添加一个contentView,设置好它们之间的constraints,contentView务必要和scrollView的四个边界都要有constraint。
  2. 定义contentViewWidth ConstraintHeight Constraint,并将constraint的Placeholder的属性勾上:Remove at build time。此时仅仅用作布局,在build time时是被remove掉的。
  3. Class-viewDidLayoutSubviews方法中手动添加上一步的Width ConstraintHeight Constraint
[self.scrollContentView addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollContentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:self.scrollView.frame.size.width * 2]];
[self.scrollContentView addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollContentView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:self.scrollView.frame.size.height]];

如果对于UISplitViewController,在-presentDetailViewController后,原有detailViewController的frame会有所改变,那么可以用 delay执行 的方式来解决下。

[self performSelector:@selector(addConstraints) withObject:nil afterDelay:0.1];

Preface

在对UIScrollView进行AutoLayout布局时,会比使用其他控件更麻烦一些。

UIScrollView有一个contentSize属性,其定义了UIScrollView可滚动内容的大小。以前用纯代码的方式时,我们会直接对这个属性赋值,定义其大小。在AutoLayout中,我们不会直接使用这个属性,而contentSize是由其内容的约束来实现自动赋值。所以,我们需要对UIScrollView和它的content分别添加约束。

Masonry

Apple官方文档中采用了Visual Format Language的方式来定义和使用NSLayoutConstraints,不过,我们还可以有更好的使用方式:Masonry

Harness the power of AutoLayout NSLayoutConstraints with a simplified, chainable and expressive syntax.

Usage

  1. Storyboard中添加UIScrollView,并添加其constraints。
  2. 新建ContentView.xib,继承自UIView,作为UIScrollView的内容视图,方便在IB中编辑。留意将Simulated Metrics Size设置为Freeform
  3. ContentView.xib中布局各个subview,并添加相应的constraints。
  4. 新建一个Class:ContentView,并将ContentView.xib的类型定义为ContentView
  5. ContentView.xib中需要依据UIScrollView大小进行改变的constraints,在ContentView.h中建立IBOutlet连接。
@interface ContentView : UIView
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *widthConstrait;
@end

6 . 实例化ContentView,并建立constraint让contentView的四个边界与scrollView的四个边界相同。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    contentView = [[[NSBundle mainBundle] loadNibNamed:@"ContentView" owner:self options:nil] objectAtIndex:0];
    [self.scrollView addSubview:contentView];
    
    [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(contentView);
    }];
}

7 . 在AutoLayout布局生效后,根据scrollView的实际宽高调整contentView的外连constraint,再借此调整contentView自身宽高的大小。

- (void)viewDidLayoutSubviews {
    contentView.widthConstrait.constant = self.scrollView.frame.size.width;
    contentView.heightConstraint.constant = self.scrollView.frame.size.height;
    
    [contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.width.equalTo([NSNumber numberWithFloat:contentView.widthConstrait.constant * 3]);
        make.height.equalTo([NSNumber numberWithFloat:contentView.heightConstraint.constant]);
    }];
    
    [super viewDidLayoutSubviews];
}

Demo

做了一个demo,放在GitHub上了。

Reference

tuts+

十七蝉