在iOS的UI开发中,frame和bounds是两个非常容易搞混的概念,而很多开发者在实际项目中也很少去区分,因此会导致出现一些意想不到的问题。本篇博客以实际代码的方式来学习frame和bounds的使用。相关示例代码上传至 https://github.com/chenyufeng1991/FrameAndBounds ,欢迎大家下载查看。

(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是一样的。原点都是在左上角。长宽正好是整个屏幕的宽高。

(2)frame和bounds难道都是一样的吗?当然不是。现在我们对一个View做一个旋转动画。

    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));}}];

动画效果如下:

我们让一个正方形旋转90度,在动画开始前和结束后分别打印frame和bounds,打印结果如下:

此时可以看到,在动画开始前,frame和bounds也变得不一样了。在旋转动画后,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发生了较大的变化,其实旋转后的frame变成了如下:

旋转后:

旋转前:

旋转后,左上角origin的x,y发生了改变,size的height,width也 发生了改变,所以frame也就改变了。我们可以把frame理解为所占区域,其实旋转后的占用区域是发生改变的。但是为什么bounds没有改变呢?

View在旋转过程中,其实自己的坐标系统并没有发生改变,bounds中的origin只能通过setBounds方法修改。 根据英文中的意思,bounds就是边界的意思,在旋转过程中,View的边界长短并没有发生改变,所以bounds的size也就没有改变。

所以我做个小小的别名:把frame理解为占用区域,把bounds理解为边界。

(3)我们把一个子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 强制将自己坐标系的左上角点改为(-30,-30)。那么真正的原点(0,0)自然向右下角偏移(30,30);// 注意:setBounds中的(x,y)只改变自己的坐标系统。子view的bounds和frame并不会改变。[view02 setBounds:CGRectMake(-30, -30, 200, 200)];} completion:^(BOOL finished) {[self printFrameAndBounds:view02 viewOfSub:view02_sub];}];

打印结果如下:

运行效果图如下:

我们通过setBounds把父View的origin=(0,0)改为了(-30,-30), 发现子View向右下方发生了移动。我们来分析一下原因。

我们刚刚提到,setBounds可以改变自己View的坐标系,父View强制把自己左上角的原点(0,0)坐标改为了(-30,-30),但是对于子View.frame.origin=(0,0)来说,它的x,y没有发生改变,仍然是(0,0),   由于左上角已经改为(-30,-30),所以真正的原点(0,0)向右下方移动,所以子View也就向右下方移动了。

做一个小小的总结:

-- 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也改变了。所以我做一个小小的总结:

-- 更改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改变大小是完全不一样的,setFrame改变长宽是从左上角原点进行缩放的,固定的是原点。而setBounds则固定的是center。

一句话说:使用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));
}

个人总结了一下:

-- 如果想修改view的位置而不影响其他,修改自身frame的位置;想修改view的大小,修改frame的大小或者bounds的大小(考虑相对位置的改变)。

-- 如果想修改view的所有子view的位置,修改view的bounds的位置(父容器坐标系)。

个人建议,想要查看某个变量的改变效果,可以使用我们初高中实验中的“单一变量原则”,也就是一次代码中只改变一个变量来运行,这样就能很方便的知道某个变量的作用了。具体可以参考Github中的demo。

iOS开发——frame和bounds详解相关推荐

  1. IOS开发学习笔记-----UILabel 详解

    IOS开发学习笔记-----UILabel 详解 01 //创建uilabel 02 UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMa ...

  2. iOS 开发之照片框架详解

    一. 概要 在 iOS 设备中,照片和视频是相当重要的一部分.最近刚好在制作一个自定义的 iOS 图片选择器,顺便整理一下 iOS 中对照片框架的使用方法.在 iOS 8 出现之前,开发者只能使用 A ...

  3. IOS开发中单例模式使用详解

    第一.基本概念 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问. 第二.在IOS中使用单例模式的情 ...

  4. [iOS开发]frame和bounds

    简述 Frame: 视图的位置和大小使用是父视图的坐标系,所以将视图放置在父级中这一点就很重要. Bounds:视图的位置和大小,使用的是其自己的坐标系,而对于这一点而言将视图的内容或子视图放置在其自 ...

  5. ios开发---URL Schemes 使用详解-app协议

    用原生 iOS 的人分两种,懂 URL Schemes 的和不懂的. 前者是「魔法师」,后者是「麻瓜」. URL Schemes 应用在 iOS 上已经很久了.对于使用者来说,在沙盒机制下的 iOS ...

  6. 【iOS开发必收藏】详解iOS应用程序内使用IAP/StoreKit付费、沙盒(SandBox)测试、创建测试账号流程!2012-6-25日更新iap恢复

    转载自:http://www.himigame.com/iphone-cocos2d/550.html 本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原 ...

  7. 【iOS开发必收藏】详解iOS应用程序内使用IAP/StoreKit付费、沙盒(SandBox)测试、创建测试账号流程!...

    为什么80%的码农都做不了架构师?>>>    Himi  原创, 欢迎转载,转载请在明显处注明! 谢谢. 原文地址:http://blog.csdn.net/xiaominghim ...

  8. iOS开发——深拷贝与浅拷贝详解

    深拷贝和浅拷贝这个问题在面试中常常被问到,而在实际开发中,只要稍有不慎,就会在这里出现问题.尤其对于初学者来说,我们有必要来好好研究下这个概念.我会以实际代码来演示,相关示例代码上传至 这里 . 首先 ...

  9. iOS开发那些事-Passbook详解与开发案例

    Passbook是iOS 6的新功能,只能在iPhone和iPod touch设备中使用.它可以帮助我们管理商家发放的电子会员卡.积分卡. 优惠券等.这将对未来电子商务产生深远的影响.商家通过发放会员 ...

最新文章

  1. 显卡在电脑什么位置_告诉你什么配置的电脑显卡/GPU才能播放4K电影视频
  2. Error:java: 无效的标记 -version 编译错误的解决办法
  3. 监控url_熬夜之作:一文带你了解Cat分布式监控
  4. 入门微信小程序(含实战) [第九篇] -- 下拉刷新和上拉加载
  5. IDEA打造快捷属性 摆脱鼠标 高效操作
  6. mysql i优化_mysql优化 - ifeixiang的个人页面 - OSCHINA - 中文开源技术交流社区
  7. Linux多进程编程(2)
  8. 如何从C快速过渡到C++
  9. ubuntu14.04 下 mysql 存储目录迁移
  10. css中 div圆角边框样式,DIV+CSS圆角边框 - 前端LOVER - 博客园
  11. z世代消费力白皮书_猫哥清华新传考研|如何让Z世代粉上你?
  12. vue中computer和watch的区别和使用
  13. asp.net开发wap程序必备:识别来访手机品牌型号【来源网络】
  14. Python基础入门实验3附加题
  15. 试用Riya-带有人脸识别功能的在线照片服务
  16. 论文经验 - 计算机视觉(CV)方向
  17. VMware虚拟机安装Windows11(无需设置TMP密码)
  18. 理解ConstraintLayout性能上的好处(转载,仅供学习)
  19. [python项目] 项目概述
  20. word不能复制粘贴,提示激活宏

热门文章

  1. 在线硬盘存储计算机,硬盘存储
  2. C语言每日一练——第133天:打鱼还是晒网
  3. python股票数据简单分析
  4. 《C语言程序设计》江宝钏主编-习题8-4-复制字串!!!
  5. 数值分析笔记_3 埃尔米特插值
  6. 中标麒麟kylinV10操作系统无法识别光驱,插入光驱没反应
  7. IOT语义互操作性之语义
  8. 2021阿里云服务器购买攻略-618年中大促专场
  9. 解决“com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536”问题
  10. 软件测试之测试用例设计(三)