引言
相信不少初学者都会对这个属性比较困惑吧。其实我也是.:)
所以,写着篇文章有两个初衷:一是为新人释义答惑;二是,看了好些文章,发现理解的有些问题,想纠正下。
什么是bounds
看了官方文档和这篇博客Understanding UIScrollView才恍然大悟:原来bound就是定义了一个视窗(viewport)啊。仅此而已,并不涉及到坐标变换之类的(我看了些文章,要么就是照抄斯坦福大学的视频,要么就是拿坐标变换、相对位置说事)。好吧,说的好简单。。。请继续往下看。
bounds就是一个视窗,不涉及坐标变换
为了验证bound不涉及坐标变换,我们首先自定义一个UIView GSCoordinateView
:标出UIView的原点位置。然后添加两个view:parentView
和childView
。childView
添加到parentView
之中,parentView
添加到根视图中。最后,改变parentView
视图的bounds属性,观察原点的位置以确定是否发生了坐标变换。
- 标原点
很简单,就是用(0,0)
标出原点的位置。
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
// Drawing code
NSDictionary *attributes=@{NSFontAttributeName:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]};
NSAttributedString *originString=[[NSAttributedString alloc] initWithString:@"(0,0)" attributes:attributes];
CGSize size=[originString size];
CGRect originRect=CGRectMake(0, 0, size.width, size.height);
[originString drawInRect:originRect];
}
- 设置视图
// setup view
self.view.backgroundColor=[UIColor whiteColor];
// set up parent view
self.parentView=[[GSCoordinateView alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
self.parentView.contentMode=UIViewContentModeRedraw;
self.parentView.backgroundColor=[UIColor cyanColor];
[self.view addSubview:self.parentView];
// set up child view
self.childView=[[GSCoordinateView alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];
self.childView.contentMode=UIViewContentModeRedraw;
self.childView.backgroundColor=[UIColor purpleColor];
[self.parentView addSubview:self.childView];
// set up restore button
UIButton *restoreButton=[UIButton buttonWithType:UIButtonTypeRoundedRect];
[restoreButton setTitle:@"Restore" forState:UIControlStateNormal];
restoreButton.frame=CGRectMake(8, 300, 100, 30);
[restoreButton addTarget:self action:@selector(restore) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:restoreButton];
// set up change bound button
UIButton *changeBoundButton=[UIButton buttonWithType:UIButtonTypeRoundedRect];
[changeBoundButton setTitle:@"Change Bound" forState:UIControlStateNormal];
changeBoundButton.frame=CGRectMake(76, 300, 150, 30);
[changeBoundButton addTarget:self action:@selector(changeBound) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:changeBoundButton];
注意: view的contentMode
要设置成UIViewContentModeRedraw
。否则,更改bounds后不会重绘。
官方的解释:
**The size of the bounds rectangle is coupled to the size of the frame rectangle, so that changes to one affect the other. ** Changing the bounds size grows or shrinks the view relative to its center point. The coordinates of the bounds rectangle are always specified in points.
Changing the frame rectangle automatically redisplays the receiver without invoking the drawRect: method. If you want the drawRect: method invoked when the frame rectangle changes, set the contentMode property to UIViewContentModeRedraw.
- 更改及还原
parentView
的bounds
- (void)restore {
self.parentView.bounds=CGRectMake(0, 0, 200, 200);
}
- (void)changeBound {
self.parentView.bounds=CGRectMake(-30, -30, 200, 200);
}
- 结果确认
-
默认
- 更改bounds后
可以看出,parentView
的原点并不是左上角位置,没有涉及到坐标系的变换。bounds只是定义了视图显示的窗口而已。 The bounds rectangle represents the visible portion of the view. That's it.
总结
遇到问题还是要弄清楚,多查资料,不要人云亦云。技术债迟早要还的。如果有疑惑,自己可以spike一下,验证自己的理解是否正确。另外Understanding UIScrollView值得读下,博主教你如何自己实现UIScrollView
。代码已上传Github。