Frame and bounds of the difference between UIView

UIView related focus.


frame: the size and location of the parent view in the view coordinate system. (Reference point, the coordinate system of the father)
bounds: the view position and size of the local coordinate system. (Reference point, the local coordinate system, is equivalent ViewB own coordinate system, in order starting from 0,0)
Center: the center point of the view position and size of the parent view coordinate system. (Reference point, the coordinate system of the father)

Practical examples

Demo:https://github.com/peilinghui/BokeDemo/tree/master/FrameAndBoundsDemo

Rotating a Custom View

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22


UIView *View1 = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 50,50)];
View1.backgroundColor = [UIColor redColor];
[self.view addSubview:View1];
NSLog(@"自定义子view的self.view.frame = %@",NSStringFromCGRect(View1.frame));
//自定义子view的self.view.frame = {{100, 100}, {50, 50}}
NSLog(@"自定义子view的self.view.bounds=%@",NSStringFromCGRect(View1.bounds));
//自定义子view的self.view.bounds={{0, 0}, {50, 50}}

[UIView transitionWithView:View1 duration:2 options:0 animations:^{
View1.transform = CGAffineTransformMakeRotation(M_PI_4);
}completion:^(BOOL finished){
if (finished)
{
NSLog(@"旋转后子view的self.view.frame = %@",NSStringFromCGRect(View1.frame));
//旋转后子view的self.view.frame = {{89.644660940672622, 89.644660940672622}, {70.710678118654755, 70.710678118654755}}

NSLog(@"旋转后子view的self.view.bounds=%@",NSStringFromCGRect(View1.bounds));
//旋转后子view的self.view.bounds={{0, 0}, {50, 50}}
}
}];



在旋转动画后,frame发生改变,bounds依然没变。下面的结论:

  • frame的位置是根据父容器来计算的,正方形在动画开始前的x=100,y=100是相对于self.view的坐标系统而言的,从而确定当前视图在父视图中的位置。
  • bounds的x,y是根据自己的坐标系统而言的。没错,每个view都有自己的坐标系。以自己左上角点为坐标原点。所以bounds的x,y默认为(0,0),除非调用setBounds方法;
  • frame的size不一定等于bounds的size,在旋转后它们的size就不一样了。

把frame理解为占用区域,把bounds理解为边界。View在旋转过程中,其实自己的坐标系统并没有发生改变,bounds中的origin只能通过setBounds方法修改。

把一个子View放到父View中,改变父View的bounds

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
UIView *fatherView = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 200, 200)];
fatherView.backgroundColor = [UIColor yellowColor];
[self.view addSubview:fatherView];

UIView *sunView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 50, 50)];
sunView.backgroundColor = [UIColor redColor];
[fatherView addSubview:sunView];

NSLog(@"父view的frame = %@,bounds=%@,中心点=:%@",NSStringFromCGRect(fatherView.frame),NSStringFromCGRect(fatherView.bounds),NSStringFromCGPoint(fatherView.center));
//父view的frame = {{100, 100}, {200, 200}},bounds={{0, 0}, {200, 200}},中心点=:{200, 200}

NSLog(@"子view的frame = %@,bounds=%@,中心点=:%@",NSStringFromCGRect(sunView.frame),NSStringFromCGRect(sunView.bounds),NSStringFromCGPoint(sunView.center));
//子view的frame = {{0, 0}, {50, 50}},bounds={{0, 0}, {50, 50}},中心点=:{25, 25}

//1. 改变父View的bounds的位置,父view的bounds改变了
[UIView animateWithDuration:4 animations:^{
[fatherView setBounds:CGRectMake(30, 30, 200, 200)];
}completion:^(BOOL finished){
NSLog(@"改变父坐标bounds的位置后父view的frame = %@,bounds=%@,中心点=:%@",NSStringFromCGRect(fatherView.frame),NSStringFromCGRect(fatherView.bounds),NSStringFromCGPoint(fatherView.center));
// 改变父坐标bounds的位置后父view的frame = {{100, 100}, {200, 200}},bounds={{30, 30}, {200, 200}},中心点=:{200, 200}
NSLog(@"改变父坐标bounds的位置后子view的frame = %@,bounds=%@,中心点=:%@",NSStringFromCGRect(sunView.frame),NSStringFromCGRect(sunView.bounds),NSStringFromCGPoint(sunView.center));
//改变父坐标bounds的位置后子view的frame = {{0, 0}, {50, 50}},bounds={{0, 0}, {50, 50}},中心点=:{25, 25}
}];



setBounds 强制将自己坐标系的左上角点改为(30,30)。那么真正的原点(0,0)自然向右上角偏移(30,30);
若是setBounds设为(-30,-30) ,则子view向右下角移动,偏移(30,30)。
注意:setBounds中的(x,y)只改变自己的坐标系统。子view的bounds和frame并不会改变。
总结:

  • setBounds中的(x,y)只改变自己的坐标系统,子View的bounds和frame并不会改变;
  • setBounds是修改自己坐标系的原点位置,进而影响到子View的显示位置;
  • bounds改变位置时,改变的是子视图的位置,自身没有影响,其实就是改变了自身的坐标系原点,默认原点在左上角。

改变父View的bounds的大小

1
[fatherView setBounds:CGRectMake(0, 0,100, 100)];



使用setBounds方法减小了父View的bounds.size ,可以看到把frame也改变了。总结:

  • 更改bounds的大小,bounds的大小代表当前视图的长和宽,修改长宽后,中心点继续保持不变,长宽进行改变,通过bounds修改长宽就像是以中心点为基准点对长宽两边同时进行缩放。
  • center是根据父容器的相对位置来计算的,无论是修改父容器的bounds还是自身的bounds,都不会改变center。况且使用bounds来缩放view,都是根据center中心点来缩放的,所以center不会改变。
  • setBounds也可以修改view的大小,进而修改frame。

改子视图的bounds的位置

1
[sunView setBounds:CGRectMake(-30, -30, 50, 50)];

图像没有变化,与把一个子View放到父View中那个图一样的。

修改子视图的bounds的大小

1
[sunView setBounds:CGRectMake(0, 0, 80, 80)];



修改子视图的bounds的大小,只是把子视图以中心点为中心扩大了,改变了子视图的frame的位置和bounds,父view不受影响。

改变父view的frame的位置

1
[fatherView setFrame:CGRectMake(30, 30, 200, 200)];



从效果图上可以看到,我们改变了父View的位置和大小(坐标系原点仍然是(0,0),但是实际位置已经改变了,坐标系改变),子View的位置也改变了。但是子View的frame和bounds并没有改变。因为子View.origin是相对于父View的而言的,这并没有改变。

改变父view的frame的大小

1
[fatherView setFrame:CGRectMake(100,100,100,100)];

1
[fatherView setFrame:CGRectMake(0,0,100,100)];


setFrame改变大小和setBounds改变大小是完全不一样的,setFrame改变长宽是从左上角原点进行缩放的,固定的是原点。而setBounds则固定的是center。

一句话说:使用frame改变view大小,center改变,因为缩放参考点为左上角。使用bounds改变view大小,center不变,因为缩放参考点为center。
frame是参考父view的坐标系来设置自己左上角的位置。
设置bounds可以修改自己坐标系的原点位置,进而影响到其“子view”的显示位置。

总结:

  • 如果想修改view的位置而不影响其他,修改自身frame的位置;想修改view的大小,修改frame的大小或者bounds的大小(考虑相对位置的改变)。
  • 如果想修改view的所有子view的位置,修改view的bounds的位置(父容器坐标系)。

bounds使用场景

其实bounds我们一直在使用,就是我们使用scrollview的时候。
为什么我们滚动scrollview可以看到超出显示屏的内容。就是因为scrollview在不断改变自己的bounds,从而改变scrollview上的子view的frame,让他们的frame始终在最顶级view(window)的frame内部,这样我们就可以始终看到内容了。

向上滚动scrollview,我们就不断增加scrollview的bounds的y值,也就是不断把scrollview的本地坐标系原点向下偏移(相对于scrollview的父view的坐标系,y值越大,越向下偏移)。那么此时scrollview的子控件的frame设置的(0,0)就是不断向上偏移

假设某一时刻scrollview的坐标系原点为(0,100),那么scrollview的(0,0)位置就是相对于坐标系原点向上偏移100的距离,设置scrollview的子控件的frame为(0,0),就是设置子控件左上角在scrollview中的(0,0)位置,那么子控件就会向上偏移100,你也就看到scrollview的内容(子控件)向上滚动的效果。

我们可以不断增加fatherView的bounds的y值,来看看是不是可以达到同样的效果:fatherView不动,Sunview在不断向上滚动
理解 Scroll Views:https://objccn.io/issue-3-2/

原文:大专栏  UIView的Frame和bounds区别


Guess you like

Origin www.cnblogs.com/wangziqiang123/p/11618321.html