iOS开发——frame和bounds详解
来源:程序员人生 发布时间:2016-07-01 15:25:08 阅读次数:3135次
在iOS的UI开发中,frame和bounds是两个非常容易弄混的概念,而很多开发者在实际项目中也很少去辨别,因此会致使出现1些意想不到的问题。本篇博客以实际代码的方式来学习frame和bounds的使用。相干示例代码上传至 https://github.com/chenyufeng1991/FrameAndBounds ,欢迎大家下载查看。
(1)先来查看1个界面中的容器self.view的frame和bounds的打印结果:下面的运行结果都在iPhone5s摹拟器下进行。
NSLog(@"self.view.frame = %@",NSStringFromCGRect(self.view.frame));
NSLog(@"self.view.bounds = %@",NSStringFromCGRect(self.view.bounds));
。
在这里我们可以看到,self.view的frame和bounds是1样的。原点都是在左上角。长宽正好是全部屏幕的宽高。
(2)frame和bounds难道都是1样的吗?固然不是。现在我们对1个View做1个旋转动画。
UIView *view01 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 50, 50)];
view01.backgroundColor = [UIColor grayColor];
[self.view addSubview:view01];
NSLog(@"view01.frame = %@",NSStringFromCGRect(view01.frame));
NSLog(@"view01.bounds = %@",NSStringFromCGRect(view01.bounds));
[UIView transitionWithView:view01 duration:2 options:0 animations:^{
view01.transform = CGAffineTransformMakeRotation(M_PI_4);
} completion:^(BOOL finished) {
if (finished)
{
NSLog(@"view01.frame = %@",NSStringFromCGRect(view01.frame));
NSLog(@"view01.bounds = %@",NSStringFromCGRect(view01.bounds));
}
}];
动画效果以下:
。
我们让1个正方形旋转90度,在动画开始前和结束后分别打印frame和bounds,打印结果以下:
。
此时可以看到,在动画开始前,frame和bounds也变得不1样了。在旋转动画后,frame产生改变,bounds仍然没变。我现在告知大家下面的结论:
-- frame的位置是根据父容器来计算的,正方形在动画开始前的x=100,y=100是相对self.view的坐标系统而言的,从而肯定当前视图在父视图中的位置。
-- bounds的x,y是根据自己的坐标系统而言的。没错,每一个view都有自己的坐标系。以自己左上角点为坐标原点。所以bounds的x,y默许为(0,0),除非调用setBounds方法;
-- frame的size不1定等于bounds的size,在旋转后它们的size就不1样了。
在旋转前后,frame产生了较大的变化,其实旋转后的frame变成了以下:
旋转后:
。
旋转前:
。
旋转后,左上角origin的x,y产生了改变,size的height,width也 产生了改变,所以frame也就改变了。我们可以把frame理解为所占区域,其实旋转后的占用区域是产生改变的。但是为何bounds没有改变呢?
View在旋转进程中,其实自己的坐标系统并没有产生改变,bounds中的origin只能通过setBounds方法修改。 根据英文中的意思,bounds就是边界的意思,在旋转进程中,View的边界长短并没有产生改变,所以bounds的size也就没有改变。
所以我做个小小的别名:把frame理解为占用区域,把bounds理解为边界。
(3)我们把1个子View放到父View中,并且改变父View的bounds,来看看会产生甚么?
UIView *view02 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
view02.backgroundColor = [UIColor colorWithWhite:0.851 alpha:1.000];
[self.view addSubview:view02];
UIView *view02_sub = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
view02_sub.backgroundColor = [UIColor colorWithRed:1.000 green:0.908 blue:0.552 alpha:1.000];
[view02 addSubview:view02_sub];
[self printFrameAndBounds:view02 viewOfSub:view02_sub];
[UIView animateWithDuration:1 animations:^{
// setBounds 强迫将自己坐标系的左上角点改成(⑶0,⑶0)。那末真实的原点(0,0)自然向右下角偏移(30,30);
// 注意:setBounds中的(x,y)只改变自己的坐标系统。子view的bounds和frame其实不会改变。
[view02 setBounds:CGRectMake(⑶0, ⑶0, 200, 200)];
} completion:^(BOOL finished) {
[self printFrameAndBounds:view02 viewOfSub:view02_sub];
}];
打印结果以下:
。
运行效果图以下:
。
我们通过setBounds把父View的origin=(0,0)改成了(⑶0,⑶0), 发现子View向右下方产生了移动。我们来分析1下缘由。
我们刚刚提到,setBounds可以改变自己View的坐标系,父View强迫把自己左上角的原点(0,0)坐标改成了(⑶0,⑶0),但是对子View.frame.origin=(0,0)来讲,它的x,y没有产生改变,依然是(0,0), 由于左上角已改成(⑶0,⑶0),所以真实的原点(0,0)向右下方移动,所以子View也就向右下方移动了。
做1个小小的总结:
-- setBounds中的(x,y)只改变自己的坐标系统,子View的bounds和frame其实不会改变;
-- setBounds是修改自己坐标系的原点位置,进而影响到子View的显示位置;
-- bounds改变位置时,改变的是子视图的位置,本身没有影响,其实就是改变了本身的坐标系原点,默许原点在左上角。
(4)当父View的frame改变的时候,子View会产生甚么变化?
UIView *view02 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
view02.backgroundColor = [UIColor colorWithWhite:0.851 alpha:1.000];
[self.view addSubview:view02];
UIView *view02_sub = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
view02_sub.backgroundColor = [UIColor colorWithRed:1.000 green:0.908 blue:0.552 alpha:1.000];
[view02 addSubview:view02_sub];
[self printFrameAndBounds:view02 viewOfSub:view02_sub];
[UIView animateWithDuration:1 animations:^{
[view02 setFrame:CGRectMake(0, 250, 150, 150)];
} completion:^(BOOL finished) {
[self printFrameAndBounds:view02 viewOfSub:view02_sub];
}];
打印结果以下:
。
运行效果动画:
。
从效果图上可以看到,我们改变了父View的位置和大小(坐标系原点依然是(0,0),但是实际位置已改变了,坐标系改变),子View的位置也改变了。但是子View的frame和bounds并没有改变。由于子View.origin是相对父View的而言的,这并没有改变。
(5)我们上述都只改变了bounds的位置,而没有改变bounds的大小,我们来看看改变bounds的大小会产生甚么?
UIView *view02 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
view02.backgroundColor = [UIColor colorWithWhite:0.851 alpha:1.000];
[self.view addSubview:view02];
UIView *view02_sub = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
view02_sub.backgroundColor = [UIColor colorWithRed:1.000 green:0.908 blue:0.552 alpha:1.000];
[view02 addSubview:view02_sub];
[self printFrameAndBounds:view02 viewOfSub:view02_sub];
[UIView animateWithDuration:1 animations:^{
[view02 setBounds:CGRectMake(0, 0, 200, 200)];
} completion:^(BOOL finished) {
[self printFrameAndBounds:view02 viewOfSub:view02_sub];
}];
打印结果以下:
。
运行动画效果以下:
。
我们使用setBounds方法增大了父View的bounds.size ,可以看到把frame也改变了。所以我做1个小小的总结:
-- 更改bounds的大小,bounds的大小代表当前视图的长和宽,修改长宽后,中心点继续保持不变,长宽进行改变,通过bounds修改长宽就像是以中心点为基准点对长宽两边同时进行缩放。
-- center是根据父容器的相对位置来计算的,不管是修改父容器的bounds还是本身的bounds,都不会改变center。况且使用bounds来缩放view,都是根据center中心点来缩放的,所以center不会改变。
-- setBounds也能够修改view的大小,进而修改frame。
(6)除有setBounds方法,一样有setFrame方法,我们来看看使用setFrame改变View的大小会产生甚么?
UIView *viewFather = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
viewFather.backgroundColor = [UIColor colorWithWhite:0.741 alpha:1.000];
[self.view addSubview:viewFather];
UIView *viewSub = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 50, 80)];
viewSub.backgroundColor = [UIColor colorWithRed:1.000 green:0.999 blue:0.721 alpha:1.000];
[viewFather addSubview:viewSub];
// (6)修改父视图的frame的大小。父容器的center改变,子视图的center不变。
[self printFrameAndBounds:viewFather viewOfSub:viewSub];
[UIView animateWithDuration:3 animations:^{
[viewFather setFrame:CGRectMake(50, 50, 250, 250)];
} completion:^(BOOL finished) {
[self printFrameAndBounds:viewFather viewOfSub:viewSub];
}];
打印结果以下:
。
动画效果以下:
。
仔细视察可以看到,setFrame改变大小和setBounds改变大小是完全不1样的,setFrame改变长宽是从左上角原点进行缩放的,固定的是原点。而setBounds则固定的是center。
1句话说:使用frame改变view大小,center改变,由于缩放参考点为左上角。使用bounds改变view大小,center不变,由于缩放参考点为center。
(7)为了上面打印frame,bounds,centre的方便,上面触及打印父子View方法调用的printFrameAndBounds方法实现以下:
- (void)printFrameAndBounds:(UIView *)viewOfFather viewOfSub:(UIView *)viewOfSub
{
NSLog(@"viewOfFather.frame = %@;viewOfFather.bounds = %@;viewOfFather.center = %@",NSStringFromCGRect(viewOfFather.frame),NSStringFromCGRect(viewOfFather.bounds),NSStringFromCGPoint(viewOfFather.center));
NSLog(@"viewOfSub.frame = %@;viewOfSub.bounds = %@;viewOfSub.center = %@",NSStringFromCGRect(viewOfSub.frame),NSStringFromCGRect(viewOfSub.bounds),NSStringFromCGPoint(viewOfSub.center));
}
个人总结了1下:
-- 如果想修改view的位置而不影响其他,修改本身frame的位置;想修改view的大小,修改frame的大小或bounds的大小(斟酌相对位置的改变)。
-- 如果想修改view的所有子view的位置,修改view的bounds的位置(父容器坐标系)。
个人建议,想要查看某个变量的改变效果,可使用我们初高中实验中的“单1变量原则”,也就是1次代码中只改变1个变量来运行,这样就可以很方便的知道某个变量的作用了。具体可以参考Github中的demo。
生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠