UIView框架,边界和中心

我想知道如何以正确的方式使用这些属性。

据我所知, frame可以从我创建的视图的容器中使用。 它设置相对于容器视图的视图位置。 它还设置了该视图的大小。

也可以从我创建的视图的容器中使用center 。 该属性更改视图相对于其容器的位置。

最后, bounds是相对于视图本身。 它改变了可视区域的视图。

你能给更多关于framebounds之间的关系的信息吗? clipsToBoundsmasksToBounds属性怎么样?

由于我问了很多次的问题,我会提供一个详细的答案。 如果你想添加更多正确的内容,随意修改它。

首先回顾一下这个问题:框架,界限,中心和他们的关系。

框架视图的frameCGRect )是其矩形在超superview坐标系中的位置。 默认情况下,它从左上角开始。

边界视图boundsCGRect )在其自己的坐标系中表示一个视图矩形。

中心 center是一个用超superview坐标系表示的CGPoint ,它决定了视图的确切中心点的位置。

UIView +的位置来看,这些是以前的属性之间的关系(它们在代码中不起作用,因为它们是非正式方程):

  • frame.origin = center - (bounds.size / 2.0)

  • center = frame.origin + (bounds.size / 2.0)

  • frame.size = bounds.size

注:如果旋转视图,则这些关系不适用。 欲了解更多信息,我会建议你看看从厨房抽屉基于斯坦福CS193p当然拍摄下面的图像。 学分去@Rhubarb

框架,边界和中心

使用该frame可以在其superview重新定位和/或调整视图的大小。 通常可以从superview ,例如,当你创建一个特定的子视图。 例如:

 // view1 will be positioned at x = 30, y = 20 starting the top left corner of [self view] // [self view] could be the view managed by a UIViewController UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)]; view1.backgroundColor = [UIColor redColor]; [[self view] addSubview:view1]; 

当你需要在view内绘制坐标时,你通常会引用bounds 。 一个典型的例子可能是在一个view内绘制一个子视图作为第一个子视图的插图。 绘制子视图需要知道超视图的bounds 。 例如:

 UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(50.0f, 50.0f, 400.0f, 400.0f)]; view1.backgroundColor = [UIColor redColor]; UIView* view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)]; view2.backgroundColor = [UIColor yellowColor]; [view1 addSubview:view2]; 

当您更改视图的bounds时会发生不同的行为。 例如,如果更改bounds size ,则frame更改(反之亦然)。 变化发生在视图的center 。 使用下面的代码,看看会发生什么:

 NSLog(@"Old Frame %@", NSStringFromCGRect(view2.frame)); NSLog(@"Old Center %@", NSStringFromCGPoint(view2.center)); CGRect frame = view2.bounds; frame.size.height += 20.0f; frame.size.width += 20.0f; view2.bounds = frame; NSLog(@"New Frame %@", NSStringFromCGRect(view2.frame)); NSLog(@"New Center %@", NSStringFromCGPoint(view2.center)); 

而且,如果更改bounds origin则会更改其内部坐标系的origin 。 默认情况下, origin位于(0.0, 0.0) (左上角)。 例如,如果您更改view1origin ,则可以看到(如果需要,请注释以前的​​代码),现在view2左上角触及view1 。 动机很简单。 你说view1它的左上角现在是位置(20.0, 20.0)但是由于view2frame origin是从(20.0, 20.0) ,所以它们将重合。

 CGRect frame = view1.bounds; frame.origin.x += 20.0f; frame.origin.y += 20.0f; view1.bounds = frame; 

origin代表了view在其超superview中的位置,但描述了bounds中心的位置。

最后, boundsorigin不是相关的概念。 两者都可以导出视图的frame (请参阅前面的等式)。

View1的案例研究

以下是使用以下代码片段时发生的情况。

 UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)]; view1.backgroundColor = [UIColor redColor]; [[self view] addSubview:view1]; NSLog(@"view1's frame is: %@", NSStringFromCGRect([view1 frame])); NSLog(@"view1's bounds is: %@", NSStringFromCGRect([view1 bounds])); NSLog(@"view1's center is: %@", NSStringFromCGPoint([view1 center])); 

相对的形象。

在这里输入图像描述

这而不是如果我改变[self view]界限如下所示会发生什么。

 // previous code here... CGRect rect = [[self view] bounds]; rect.origin.x += 30.0f; rect.origin.y += 20.0f; [[self view] setBounds:rect]; 

相对的形象。

在这里输入图像描述

在这里,你可以对[self view]说,它的左上角现在是位置(30.0,20.0),但是由于view1的帧起点从(30.0,20.0)开始,它们将重合。

额外的参考 (如果你想要更新与其他参考)

  • UIView几何
  • UIView框架和边界

关于clipsToBounds (源苹果文档)

将此值设置为YES会导致子视图被剪裁到接收者的边界。 如果设置为NO,那么其帧超出接收器可见边界的子视图不会被剪切。 默认值是NO。

换句话说,如果视图的frame(0, 0, 100, 100) 0,0,100,100 (0, 0, 100, 100) ,其子视图是(90, 90, 30, 30) 90,90,30,30 (90, 90, 30, 30) ,则只能看到该子视图的一部分。 后者不会超出父视图的范围。

masksToBounds相当于clipsToBounds 。 而不是UIView ,这个属性被应用到CALayer 。 在引擎盖下, clipsToBounds调用masksToBounds 。 进一步的参考看看如何是UIView的clipsToBounds和CALayer的masksToBounds之间的关系? 。

这个问题已经有了很好的答案,但是我想补充一些更多的图片。 我的完整答案在这里。

为了帮助我记住框架 ,我想起了墙上一个相框 。 就像一张图片可以在墙上的任何地方移动一样,一个视图框架的坐标系就是超视图。 (wall = superview,frame = view)

为了帮助我记住界限 ,我想到了篮球场的界限 。 法院内部的篮球就像视野范围内的坐标系在视野内一样。 (球场=观点,篮球/球员=球员内景)

像框架一样, view.center也在superview的坐标中。

框架与边界 – 示例1

黄色矩形表示视图的框架。 绿色矩形表示视图的边界。 两幅图像中的红点代表框架的原点或其坐标系内的边界。

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

在这里输入图像描述


例2

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

在这里输入图像描述


例3

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

在这里输入图像描述


例4

这与示例2相同,除了这次显示视图的全部内容,如果它没有被剪裁到视图的边界。

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

在这里输入图像描述


例5

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

在这里输入图像描述

再次,看到我的答案与更多的细节。

我发现这个图像对理解框架,边界等最有帮助

在这里输入图像描述

当图像旋转时请注意frame.size != bounds.size

  • 框架属性包含框架矩形,它在其超级视图的坐标系中指定视图的大小和位置。
  • bounds属性包含边界矩形,它在视图自己的本地坐标系统中指定视图(及其内容原点)的大小。
  • center属性包含superview坐标系中视图的已知中心点。

我想如果你从CALayer的角度来看,一切都更加清晰。

框架实际上并不是视图或图层的独特属性,它是一个虚拟属性,根据边界,位置( UIView的中心)和变换计算。

所以基本上这些图层/视图布局是如何由这三个属性(和anchorPoint)真正决定的,而这三个属性中的任何一个都不会改变任何其他属性,就像变化的变换不会改变边界一样。

有很好的答案,对这篇文章有详细的解释。 我只想指出,在WWDC 2011视频中了解UIKit渲染从@ 4:22开始直到20:10,对于框架,边界,中心,变换,边界起源的含义有另一种解释

读完上面的答案后,在这里加上我的解释。

假设在线浏览, 网络浏览器是决定网页显示位置和显示大小的frame 。 浏览器的滚动条是你的bounds.origin ,决定网页的哪一部分将被显示。 bounds.origin很难理解。 学习的最好方法是创建单一视图应用程序,试着修改这些参数,看看子视图是如何改变的。

 - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(100.0f, 200.0f, 200.0f, 400.0f)]; [view1 setBackgroundColor:[UIColor redColor]]; UIView *view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)]; [view2 setBackgroundColor:[UIColor yellowColor]]; [view1 addSubview:view2]; [[self view] addSubview:view1]; NSLog(@"Old view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center)); NSLog(@"Old view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center)); // Modify this part. CGRect bounds = view1.bounds; bounds.origin.x += 10.0f; bounds.origin.y += 10.0f; // incase you need width, height //bounds.size.height += 20.0f; //bounds.size.width += 20.0f; view1.bounds = bounds; NSLog(@"New view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center)); NSLog(@"New view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center));