AutoLayout & UIScrollView
Update
今天看到了一个更直观更简单的办法:
- 为
scrollView
添加一个contentView
,设置好它们之间的constraints,contentView
务必要和scrollView
的四个边界都要有constraint。 - 定义
contentView
的Width Constraint和Height Constraint,并将constraint的Placeholder
的属性勾上:Remove at build time。此时仅仅用作布局,在build time时是被remove掉的。 - 在Class的
-viewDidLayoutSubviews
方法中手动添加上一步的Width Constraint和Height 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
- 在Storyboard中添加UIScrollView,并添加其constraints。
- 新建ContentView.xib,继承自UIView,作为UIScrollView的内容视图,方便在IB中编辑。留意将
Simulated Metrics Size
设置为Freeform
。 - 在ContentView.xib中布局各个subview,并添加相应的constraints。
- 新建一个Class:ContentView,并将ContentView.xib的类型定义为ContentView。
- 将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上了。