UIView及其子类都具有属性framebounds 。 有什么不同?


#1楼

框架相对于其超视图定义UIView的矩形。

bounds rect是定义NSView坐标系的值范围

即,此矩形中的任何内容都将实际显示在UIView中。


#2楼

UIView的边界是矩形 ,表示为相对于其自身坐标系(0,0)的位置(x,y)和大小(宽度,高度)。

UIView的框架是矩形 ,表示为相对于其所包含的超视图的位置(x,y)和大小(宽度,高度)。

因此,想象一个大小为100x100(宽x高)的视图位于其超视图的25,25(x,y)处。 以下代码打印出此视图的边界和框架:

// This method is in the view controller of the superview
- (void)viewDidLoad {[super viewDidLoad];NSLog(@"bounds.origin.x: %f", label.bounds.origin.x);NSLog(@"bounds.origin.y: %f", label.bounds.origin.y);NSLog(@"bounds.size.width: %f", label.bounds.size.width);NSLog(@"bounds.size.height: %f", label.bounds.size.height);NSLog(@"frame.origin.x: %f", label.frame.origin.x);NSLog(@"frame.origin.y: %f", label.frame.origin.y);NSLog(@"frame.size.width: %f", label.frame.size.width);NSLog(@"frame.size.height: %f", label.frame.size.height);
}

这段代码的输出是:

bounds.origin.x: 0
bounds.origin.y: 0
bounds.size.width: 100
bounds.size.height: 100frame.origin.x: 25
frame.origin.y: 25
frame.size.width: 100
frame.size.height: 100

因此,我们可以看到,在这两种情况下,无论我们是在查看边界还是框架,视图的宽度和高度都是相同的。 不同的是视图的x,y定位。 在边界的情况下,x和y坐标为0,0,因为这些坐标相对于视图本身。 但是,帧x和y坐标是相对于父视图中视图的位置(我们之前说的是25,25)。

还有一个很棒的演示文稿 ,涵盖了UIViews。 请参阅幻灯片1-20,其中不仅解释了帧和边界之间的差异,还显示了可视化示例。


#3楼

尝试运行下面的代码

- (void)viewDidLoad {[super viewDidLoad];UIWindow *w = [[UIApplication sharedApplication] keyWindow];UIView *v = [w.subviews objectAtIndex:0];NSLog(@"%@", NSStringFromCGRect(v.frame));NSLog(@"%@", NSStringFromCGRect(v.bounds));
}

这段代码的输出是:

案例设备方向是纵向

{{0, 0}, {768, 1024}}
{{0, 0}, {768, 1024}}

案例设备方向是横向

{{0, 0}, {768, 1024}}
{{0, 0}, {1024, 768}}

显然,你可以看到框架和边界之间的区别


#4楼

简答

frame =使用父视图坐标系的视图位置和大小

  • 重要的是:将视图放在父级中

bounds =使用自己的坐标系统查看位置和大小

  • 重要的是:将视图的内容或子视图放在其自身中

详细解答

为了帮助我记住框架 ,我想到了墙上的相框 。 相框就像一个视图的边框。 我可以将照片挂在墙上的任何地方。 以同样的方式,我可以在父视图(也称为superview)中的任何地方放置视图。 父视图就像墙。 iOS中坐标系的原点是左上角。 我们可以通过将视图框的xy坐标设置为(0,0)来将我们的视图放在超视图的原点上,就像将我们的图片悬挂在墙的左上角一样。 要向右移动,增加x,将其向下移动增加y。

为了帮助我记住边界 ,我想到了一个篮球场 ,有时候篮球会被淘汰出局 。 你在整个篮球场上运球,但你并不关心球场本身的位置。 它可能在健身房,高中以外,或在你家门前。 没关系。 你只想打篮球。 同样,视图边界的坐标系统只关心视图本身。 它不知道视图在父视图中的位置。 边界的原点(默认为点(0,0))是视图的左上角。 此视图具有的任何子视图都与此相关。 就像把篮球带到球场的左前角一样。

现在,当您尝试比较帧和边界时,会出现混乱。 不过,它实际上并没有最初看起来那么糟糕。 让我们用一些图片来帮助我们理解。

帧与界限

在左边的第一张图片中,我们有一个位于其父视图左上角的视图。 黄色矩形表示视图的框架。 在右侧,我们再次看到视图,但这次没有显示父视图。 那是因为边界不知道父视图。 绿色矩形表示视图的边界。 两个图像中的红点表示帧或边界的原点

Frameorigin = (0, 0)width = 80height = 130Bounds origin = (0, 0)width = 80height = 130

因此,该图片中的框架和边界完全相同。 让我们看一下它们不同的例子。

Frameorigin = (40, 60)  // That is, x=40 and y=60width = 80height = 130Bounds origin = (0, 0)width = 80height = 130

因此,您可以看到更改框架的xy坐标会在父视图中移动它。 但是视图本身的内容看起来仍然完全一样。 边界不知道有什么不同。

到目前为止,框架和边界的宽度和高度完全相同。 但这并非总是如此。 看看如果我们顺时针旋转视图20度会发生什么。 (使用变换完成旋转。有关详细信息,请参阅文档和这些视图和图层示例 。)

Frameorigin = (20, 52)  // These are just rough estimates.width = 118height = 187Bounds origin = (0, 0)width = 80height = 130

您可以看到边界仍然相同。 他们仍然不知道发生了什么事! 但是帧值已经全部改变了。

现在可以更容易地看到框架和边界之间的区别,不是吗? 您可能不了解框架和边界的文章将视图框架定义为

...该视图相对于父视图坐标系的最小边界框,包括应用于该视图的任何变换。

请务必注意,如果转换视图,则框架将变为未定义。 实际上,我在上图中旋转的绿色边界周围绘制的黄色框架实际上并不存在。 这意味着如果您旋转,缩放或进行其他转换,则不应再使用帧值。 但是,您仍然可以使用边界值。 Apple文档警告说:

要点:如果视图的transform属性不包含identity变换,则该视图的框架是未定义的,其自动调整行为的结果也是如此。

相当不幸的是自动化....但是你可以做些什么。

Apple文档指出:

修改视图的transform属性时,将相对于视图的中心点执行所有转换。

因此,如果您确实需要在转换完成后在父级中移动视图,则可以通过更改view.center坐标来完成此view.center 。 与frame一样, center使用父视图的坐标系。

好吧,让我们摆脱旋转并专注于界限。 到目前为止,边界起源一直保持在(0,0)。 但它没有必要。 如果我们的视图有一个太大的子视图太大而无法一次显示怎么办? 我们将它变成一个带有大图像的UIImageView 。 这是我们上面的第二张图片,但这次我们可以看到我们视图的子视图的整个内容会是什么样子。

Frameorigin = (40, 60)width = 80height = 130Bounds origin = (0, 0)width = 80height = 130

只有图像的左上角可以放在视图的边界内。 现在看看如果我们改变边界的原点坐标会发生什么。

Frameorigin = (40, 60)width = 80height = 130Bounds origin = (280, 70)width = 80height = 130

框架没有在超视图中移动,但框架内的内容已更改,因为边界矩形的原点从视图的不同部分开始。 这是UIScrollView及其子类(例如, UITableView )背后的整个想法。 有关更多说明,请参阅了解UIScrollView 。

何时使用框架以及何时使用边界

由于frame在其父视图中与视图的位置相关,因此在进行向外更改时使用它,例如更改其宽度或查找视图与其父视图顶部之间的距离。

在进行向内更改时使用bounds ,例如在视图中绘制内容或排列子视图。 如果您对视图进行了一些转换,也可以使用边界来获取视图的大小。

进一步研究的文章:

Apple文档

  • 查看几何
  • 查看
  • 视图和窗口架构

相关的StackOverflow问题

  • UIView框架,边界和中心
  • UIView的框架,边界,中心,原点,何时使用什么?
  • 在iPhone中重新定位后,“不正确”的框架/窗口大小

其他资源

  • 你可能不理解框架和边界
  • iOS基础知识:框架,边界和CGGeometry
  • CS193p第5讲 - 视图,绘图,动画

练习自己

除了阅读上述文章之外,制作测试应用程序对我有很大帮助。 您可能想尝试做类似的事情。 (我从这个视频课程中得到了这个想法,但遗憾的是它不是免费的。)

以下是供您参考的代码:

import UIKitclass ViewController: UIViewController {@IBOutlet weak var myView: UIView!// Labels@IBOutlet weak var frameX: UILabel!@IBOutlet weak var frameY: UILabel!@IBOutlet weak var frameWidth: UILabel!@IBOutlet weak var frameHeight: UILabel!@IBOutlet weak var boundsX: UILabel!@IBOutlet weak var boundsY: UILabel!@IBOutlet weak var boundsWidth: UILabel!@IBOutlet weak var boundsHeight: UILabel!@IBOutlet weak var centerX: UILabel!@IBOutlet weak var centerY: UILabel!@IBOutlet weak var rotation: UILabel!// Sliders@IBOutlet weak var frameXSlider: UISlider!@IBOutlet weak var frameYSlider: UISlider!@IBOutlet weak var frameWidthSlider: UISlider!@IBOutlet weak var frameHeightSlider: UISlider!@IBOutlet weak var boundsXSlider: UISlider!@IBOutlet weak var boundsYSlider: UISlider!@IBOutlet weak var boundsWidthSlider: UISlider!@IBOutlet weak var boundsHeightSlider: UISlider!@IBOutlet weak var centerXSlider: UISlider!@IBOutlet weak var centerYSlider: UISlider!@IBOutlet weak var rotationSlider: UISlider!// Slider actions@IBAction func frameXSliderChanged(sender: AnyObject) {myView.frame.origin.x = CGFloat(frameXSlider.value)updateLabels()}@IBAction func frameYSliderChanged(sender: AnyObject) {myView.frame.origin.y = CGFloat(frameYSlider.value)updateLabels()}@IBAction func frameWidthSliderChanged(sender: AnyObject) {myView.frame.size.width = CGFloat(frameWidthSlider.value)updateLabels()}@IBAction func frameHeightSliderChanged(sender: AnyObject) {myView.frame.size.height = CGFloat(frameHeightSlider.value)updateLabels()}@IBAction func boundsXSliderChanged(sender: AnyObject) {myView.bounds.origin.x = CGFloat(boundsXSlider.value)updateLabels()}@IBAction func boundsYSliderChanged(sender: AnyObject) {myView.bounds.origin.y = CGFloat(boundsYSlider.value)updateLabels()}@IBAction func boundsWidthSliderChanged(sender: AnyObject) {myView.bounds.size.width = CGFloat(boundsWidthSlider.value)updateLabels()}@IBAction func boundsHeightSliderChanged(sender: AnyObject) {myView.bounds.size.height = CGFloat(boundsHeightSlider.value)updateLabels()}@IBAction func centerXSliderChanged(sender: AnyObject) {myView.center.x = CGFloat(centerXSlider.value)updateLabels()}@IBAction func centerYSliderChanged(sender: AnyObject) {myView.center.y = CGFloat(centerYSlider.value)updateLabels()}@IBAction func rotationSliderChanged(sender: AnyObject) {let rotation = CGAffineTransform(rotationAngle: CGFloat(rotationSlider.value))myView.transform = rotationupdateLabels()}private func updateLabels() {frameX.text = "frame x = \(Int(myView.frame.origin.x))"frameY.text = "frame y = \(Int(myView.frame.origin.y))"frameWidth.text = "frame width = \(Int(myView.frame.width))"frameHeight.text = "frame height = \(Int(myView.frame.height))"boundsX.text = "bounds x = \(Int(myView.bounds.origin.x))"boundsY.text = "bounds y = \(Int(myView.bounds.origin.y))"boundsWidth.text = "bounds width = \(Int(myView.bounds.width))"boundsHeight.text = "bounds height = \(Int(myView.bounds.height))"centerX.text = "center x = \(Int(myView.center.x))"centerY.text = "center y = \(Int(myView.center.y))"rotation.text = "rotation = \((rotationSlider.value))"}}

#5楼

frame是超视图坐标系中视图的原点(左上角)和大小,这意味着你通过改变框架原点在其超级视图中翻译视图,另一方面是边界的大小和原点自己的坐标系,所以默认情况下边界原点是(0,0)。

大多数情况下帧和边界是一致的,但是如果你有一个框架((140,65),(200,250))和边界((0,0),(200,250))的视图,例如,视图是倾斜的所以它站在它的右下角,然后边界仍然是((0,0),(200,250)),但框架不是。

框架将是封装/环绕视图的最小矩形,因此框架(如照片中)将是((140,65),(320,320))。

另一个区别是,例如,如果你有一个superView的边界是((0,0),(200,200)),这个superView有一个子视图,其框架是((20,20),(100,100)),你改变了superView边界到((20,20),(200,200)),那么subView框架仍然是((20,20),(100,100)),但是由(20,20)背景,因为它的超视图坐标系被(20, 20)。

我希望这有助于某人。


#6楼

框架相对于其SuperView而Bounds相对于其NSView。

示例:X = 40,Y = 60.还包含3个Views.This图表显示了清晰的想法。


#7楼

上面的答案很好地解释了Bounds和Frames之间的区别。

界限:视图大小和位置根据其自己的坐标系统。

框架:相对于SuperView的视图大小和位置。

然后有一个混乱,在Bounds的情况下,X,Y将始终为“0”。 事实并非如此 。 这也可以在UIScrollView和UICollectionView中理解。

当边界'x,y不为0时。
我们假设我们有一个UIScrollView。 我们实施了分页。 UIScrollView有3页,其ContentSize的宽度是屏幕宽度的三倍(假设ScreenWidth为320)。 高度是恒定的(假定为200)。

scrollView.contentSize = CGSize(x:320*3, y : 200)

添加三个UIImageViews作为子视图,并仔细查看帧的x

let imageView0 = UIImageView.init(frame: CGRect(x:0, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView1 :  UIImageView.init( frame: CGRect(x:320, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView2 :  UIImageView.init(frame: CGRect(x:640, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
  1. 第0页:当ScrollView位于0页时,界限将为(x:0,y:0,宽度:320,高度:200)

  2. 第1页:滚动并移至第1页。
    现在边界将是(x:320,y:0,宽度:320,高度:200)记住我们说过它自己的坐标系。 所以现在ScrollView的“可见部分”在320处有“x”。看看imageView1的框架。

  3. 第2页:滚动并移动到第2页界限:(x:640,y:0,宽度:320,高度:200)再次看一下imageView2的框架

对于UICollectionView的情况也是如此。 查看collectionView最简单的方法是滚动它并打印/记录它的边界,你就会明白这个想法。


#8楼

以上所有答案都是正确的,这是我对此的看法:

要区分框架和边界,CONCEPTS开发人员应该阅读:

  1. 相对于superview(一个父视图),它包含在= FRAME中
  2. 相对于自己的坐标系,确定其子视图位置= BOUNDS

“边界”令人困惑,因为它给人的印象是坐标是设置它的视图的位置。 但这些是关系,并根据框架常数进行调整。


#9楼

frame =使用父视图坐标系的视图位置和大小

bounds =使用自己的坐标系统查看位置和大小

视图使用两个矩形跟踪其大小和位置:框架矩形和边界矩形。 框架矩形使用superview的坐标系在superview中定义视图的位置和大小。 边界矩形定义绘制视图内容时使用的内部坐标系,包括原点和缩放。 图2-1显示了左边的框架矩形和右边的边界矩形之间的关系。“

简而言之,框架是superview的视图概念,边界是视图自己的想法。 具有多个坐标系,每个视图一个坐标系,是视图层次结构的一部分。

可可:框架和边界之间有什么区别?相关推荐

  1. python什么时候用框架_关于python:框架和对象之间有什么区别,什么时候应该修改另一个?...

    我开始阅读python的+=语法,无意中发现了以下文章/答案:关于的交互式代码+= 所以我注意到帧和对象之间似乎有区别. . 在全局框架中,它们指向同一对象,即使它们是不同的变量:如果 l2 += [ ...

  2. 框架和库的区别_框架和库之间的区别

    框架和库的区别 Developers often use the terms "library" and "framework" interchangeably ...

  3. 应用程序服务器和Web服务器之间有什么区别?

    应用程序服务器和Web服务器之间有什么区别? #1楼 最大的不同是Web服务器处理HTTP请求,而应用程序服务器将在任意数量的协议上执行业务逻辑. #2楼 这取决于特定的体系结构. 某些应用程序服务器 ...

  4. 科普丨数据中心、云计算、大数据之间有什么区别和联系?

    不少人把数据中心.云计算数据中心.大数据搞混淆,觉得这三者是一样的产品,其实有显著地区别,数据中心机房是一整套复杂的设施,如今,云计算即将成为信息社会的公共资源,而数据中心则是支撑云计算服务的基础设施 ...

  5. npm package.json文件中的依赖关系,devDependencies和peerDependencies之间有什么区别?

    本文翻译自:What's the difference between dependencies, devDependencies and peerDependencies in npm packag ...

  6. PHP和Node.js开发之间有什么区别

    在很长一段时间内,决定在Node.js和PHP之间进行选择是一件很麻烦的事情,但对于后端程序员来说,这一直很麻烦,但它从未影响过开发人员.但是事情很快就发生了变化,现在开发人员必须选择其中之一.Nod ...

  7. 构架、框架、设计模式之间的关系简述

    一.软件体系结构和框架的定义 软件体系结构的英文单词是"architecture". Architecture的基本词义是建筑.建筑学.建筑风格. 软件体系结构虽然根植于软件工程, ...

  8. 路由器和交换机分别起什么作用,它们之间有什么区别?

    路由器和交换机分别起什么作用,它们之间有什么区别? 计算机网络往往由许多种不同类型的网络互连连接而成.如果几个计算机网络只是在物理上连接在一起,它们之间并不能进行通信,那么这种"互连&quo ...

  9. HTML的不同版本区别,HTML4.0、XHTML、HTML5每个版本之间有什么区别

    HTML4.0.XHTML.HTML5每个版本之间有什么区别 一.基本概念: html:超文本标记语言 (Hyper Text Markup Language) xhtml:可扩展超文本标记语言,是一 ...

最新文章

  1. 微软职位内部推荐-Software Engineer II-Web app
  2. 微软自家的.Net下的JavaScript引擎——ClearScript
  3. 微软 Powertoys 推出新的实用程序,自定义键盘快捷管理
  4. 99乘法表 (输入一个数,以该数为行数输出乘法表)
  5. 排序系列02--选择排序
  6. 微信小程序首支视频广告片发布
  7. 通过Web页面获取基站位置(Web端,源码下载)
  8. 大数据,数据分析,机器学习,架构等相关系统名称名词解释
  9. sakai mysql_一个完整的Sakai安装步骤
  10. 下载verycd的方法下载电驴资源隐藏资源的最新可用方法
  11. 离散作业--求左陪集
  12. 算法课讨论 深究哈密顿图
  13. 探究人工智能辅助新时代心理学研究
  14. android平板的隐藏空间如何开启,平板电脑怎么截图和怎么隐藏游戏?
  15. 用计算机找终身伴侣,五个经典问题决定你是否找到终身伴侣
  16. 安装maskrcnn-banchmark时遇到的“AT_CHECK“ is undefined错误
  17. 第7节 蒙卡模拟计算路径依赖型期权价格
  18. ckeditor KindEditor eWebEditor WQeditor FreeTextbox Tinymce 几款在线编辑器的比较(附各版本demo下载地址)
  19. 盘点那些以“马”作为车标的汽车品牌
  20. windows 10瘦身

热门文章

  1. 算法-----------数组------------只出现一次的数字
  2. Android左边有固定文字的EditText
  3. Java、Android注解代码生成(ButterKnife原理、ViewBinding)
  4. python中标识符下划线用作开头_python python中那些双下划线开头的那些函数都是干啥用用的...
  5. PHP学习笔记-PHP与JavaScript的交互
  6. iOS 绘制圆角矩形
  7. Swift 注释规范和文档注释
  8. java_环境安装(window10)
  9. join,和循环删除,fromkeys,集合,拷贝
  10. 单变量线性回归中的梯度下降法求解代价函数的最小值