UIView frame, bounds 和 center

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

根据我的理解,frame可以从我正在创建的视图的容器中使用。 它设置了相对于容器视图的视图位置。它还设置了视图的大小

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

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

你能提供更多关于framebounds之间关系的信息吗?clipsToBoundsmasksToBounds属性呢?

227134 次浏览

因为我问的问题已经被看到很多次了,所以我将提供一个详细的答案。如果您想添加更多正确的内容,请随意修改。

首先回顾一下这个问题:框架、边界和中心以及它们之间的关系。

一个视图的frame (CGRect)是它的矩形在superview的坐标系中的位置。默认情况下,它从左上角开始。

一个视图的bounds (CGRect)在它自己的坐标系中表示一个视图矩形。

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

这些是从UIView + position中提取的前面属性之间的关系(它们在代码中不起作用,因为它们是非正式的方程):

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

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

  • frame.size = bounds.size

如果视图被旋转,这些关系不适用。为了获得进一步的信息,我建议你看看下面这张基于Stanford 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 sizeframe也会改变(反之亦然)。更改发生在视图的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更改为view1,你可以看到(如果你愿意,可以注释前面的代码)现在view2的左上角与view1的左上角接触。动机很简单。你对view1说它的左上角现在在origin0的位置,但由于view2origin2 originorigin0开始,它们将重合。

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

相对像。

enter image description here

如果我像下面这样更改[self view]边界,就会发生这种情况。

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

相对像。

enter image description here

这里你告诉[self view]它的左上角现在位于(30.0,20.0)位置,但由于view1的帧原点从(30.0,20.0)开始,它们将重合。

额外的引用(如果你需要的话,用其他引用更新)

关于clipsToBounds(来源Apple doc)

将此值设置为YES会导致子视图被剪切到边界 接收者。如果设置为NO,则其子视图的帧扩展到 接收器的可见边界没有被剪切。默认值为 没有。< / p >

换句话说,如果一个视图的frame(0, 0, 100, 100),它的子视图是(90, 90, 30, 30),你将只能看到子视图的一部分。后者不会超出父视图的边界。

masksToBounds等价于clipsToBounds。相反,此属性应用于UIView。在底层,clipsToBounds调用masksToBounds。如需进一步引用,请查看如何是UIView's clipsToBounds和CALayer's masksToBounds之间的关系?

我发现这张图对理解框架、边界等很有帮助。

enter image description here

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

我认为如果你从CALayer的角度来思考,一切都更清楚了。

Frame实际上根本不是视图或层的独特属性,它是一个虚拟属性,由边界、位置(UIView的中心)和转换计算。

所以基本上图层/视图布局是由这三个属性(和anchorPoint)决定的,这三个属性中的任何一个都不会改变任何其他属性,比如改变transform不会改变边界。

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

为了帮助我记住框架,我想到了墙上的画框。就像图片可以在墙上的任何地方移动一样,视图框架的坐标系统是父视图。(墙=父视图框架=视图)

为了帮助我记住界限,我想到了篮球场的边界。篮球在球场内的某个地方就像视图边界的坐标系在视图本身内一样。(球场=视图,篮球/球员=视图内的内容)

和框架一样,view.center也在父视图的坐标中。

框架与边界-示例1

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

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


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

enter image description here


示例2

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


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

enter image description here


示例3

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


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

enter image description here


示例4

这与示例2相同,只是这次显示的是视图的整个内容,就像它没有被剪切到视图的边界一样。

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


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

enter image description here


示例5

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


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

enter image description here

同样,更多细节请参见在这里

看完以上答案,在此加上我的解读。

假设在线浏览,web浏览器是你的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));

这篇文章有非常好的答案和详细的解释。我只是想指出,在WWDC 2011视频理解UIKit渲染中,从@4:22到20:10,有另一种对帧、边界、中心、变换、边界原点的视觉表示的解释