简体   繁体   English

UIView框架,边界和中心

[英]UIView frame, bounds and center

I would like to know how to use these properties in the right manner. 我想知道如何以正确的方式使用这些属性。

As I understand, frame can be used from the container of the view I am creating. 据我所知, frame可以从我正在创建的视图的容器中使用。 It sets the view position relative to the container view. 它设置相对于容器视图的视图位置。 It also sets the size of that view. 它还设置该视图的大小。

Also center can be used from the container of the view I'm creating. 也可以从我正在创建的视图的容器中使用center This property changes the position of the view relative to its container. 此属性更改视图相对于其容器的位置。

Finally, bounds is relative to the view itself. 最后, bounds是相对于视图本身。 It changes the drawable area for the view. 它会更改视图的可绘制区域。

Can you give more info about the relationship between frame and bounds ? 你能提供关于framebounds之间关系的更多信息吗? What about the clipsToBounds and masksToBounds properties? clipsToBoundsmasksToBounds属性怎么样?

Since the question I asked has been seen many times I will provide a detailed answer of it. 由于我问过的问题已多次出现,我将提供详细的答案。 Feel free to modify it if you want to add more correct content. 如果您想添加更多正确的内容,请随意修改它。

First a recap on the question: frame, bounds and center and theirs relationships. 首先回顾一下这个问题:框架,边界和中心以及它们之间的关系。

Frame A view's frame ( CGRect ) is the position of its rectangle in the superview 's coordinate system. 框架视图的frameCGRect )是其超superview坐标系中矩形的位置。 By default it starts at the top left. 默认情况下,它从左上角开始。

Bounds A view's bounds ( CGRect ) expresses a view rectangle in its own coordinate system. 边界视图boundsCGRect )在其自己的坐标系中表示视图矩形。

Center A center is a CGPoint expressed in terms of the superview 's coordinate system and it determines the position of the exact center point of the view. 中心 A center是以超superview的坐标系表示的CGPoint ,它确定视图的精确中心点的位置。

Taken from UIView + position these are the relationships (they don't work in code since they are informal equations) among the previous properties: UIView +位置开始,这些是之前属性中的关系(它们在代码中不起作用,因为它们是非正式方程式):

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

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

  • frame.size = bounds.size

NOTE: These relationships do not apply if views are rotated. 注意:如果旋转视图,则这些关系不适用。 For further info, I will suggest you take a look at the following image taken from The Kitchen Drawer based on Stanford CS193p course. 有关详细信息,我建议您查看以下基于斯坦福CS193p课程的厨房抽屉 图片 Credits goes to @Rhubarb . 积分归@Rhubarb所有

框架,边界和中心

Using the frame allows you to reposition and/or resize a view within its superview . 使用frame可以在其superview重新定位和/或调整视图大小。 Usually can be used from a superview , for example, when you create a specific subview. 通常可以在superview ,例如,在创建特定子视图时。 For example: 例如:

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

When you need the coordinates to drawing inside a view you usually refer to bounds . 当您需要在view内绘制坐标时,通常会引用bounds A typical example could be to draw within a view a subview as an inset of the first. 一个典型的例子可能是在view绘制一个子视图作为第一个插图。 Drawing the subview requires to know the bounds of the superview. 绘制子视图需要知道超级视图的bounds For example: 例如:

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

Different behaviours happen when you change the bounds of a view. 更改视图的bounds时会发生不同的行为。 For example, if you change the bounds size , the frame changes (and vice versa). 例如,如果更改bounds size ,则frame更改(反之亦然)。 The change happens around the center of the view. 变化发生在视图的center附近。 Use the code below and see what happens: 使用下面的代码,看看会发生什么:

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

Furthermore, if you change bounds origin you change the origin of its internal coordinate system. 此外,如果更改bounds origin ,则更改其内部坐标系的origin By default the origin is at (0.0, 0.0) (top left corner). 默认情况下, origin位于(0.0, 0.0) (左上角)。 For example, if you change the origin for view1 you can see (comment the previous code if you want) that now the top left corner for view2 touches the view1 one. 例如,如果更改view1origin ,则可以看到(如果需要,请注释前面的代码),现在view2左上角触及view1 The motivation is quite simple. 动机很简单。 You say to view1 that its top left corner now is at the position (20.0, 20.0) but since view2 's frame origin starts from (20.0, 20.0) , they will coincide. 你说view1它的左上角现在位于(20.0, 20.0)位置(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; 

The origin represents the view 's position within its superview but describes the position of the bounds center. origin表示view在其超superview中的位置,但描述了bounds中心的位置。

Finally, bounds and origin are not related concepts. 最后, boundsorigin不是相关的概念。 Both allow to derive the frame of a view (See previous equations). 两者都允许导出视图的frame (参见前面的等式)。

View1's case study View1的案例研究

Here is what happens when using the following snippet. 以下是使用以下代码段时发生的情况。

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

The relative image. 相对的形象。

在此输入图像描述

This instead what happens if I change [self view] bounds like the following. 相反,如果我更改[self view]界限,如下所示会发生什么。

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

The relative image. 相对的形象。

在此输入图像描述

Here you say to [self view] that its top left corner now is at the position (30.0, 20.0) but since view1 's frame origin starts from (30.0, 20.0), they will coincide. 在这里你要说[self view]它的左上角现在位于(30.0,20.0)位置,但由于view1的帧起点从(30.0,20.0)开始,它们将重合。

Additional references (to update with other references if you want) 其他参考 (如果需要,可与其他参考资料一起更新)

About clipsToBounds (source Apple doc) 关于clipsToBounds (源Apple文档)

Setting this value to YES causes subviews to be clipped to the bounds of the receiver. 将此值设置为YES会导致子视图被剪切到接收器的边界。 If set to NO, subviews whose frames extend beyond the visible bounds of the receiver are not clipped. 如果设置为NO,则不会剪切其帧超出接收器可见边界的子视图。 The default value is NO. 默认值为NO。

In other words, if a view's frame is (0, 0, 100, 100) and its subview is (90, 90, 30, 30) , you will see only a part of that subview. 换句话说,如果视图的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) ,您将只看到该子视图的一部分。 The latter won't exceed the bounds of the parent view. 后者不会超过父视图的范围。

masksToBounds is equivalent to clipsToBounds . masksToBounds相当于clipsToBounds Instead to a UIView , this property is applied to a CALayer . 而不是UIView ,此属性应用于CALayer Under the hood, clipsToBounds calls masksToBounds . 在引擎盖下, clipsToBounds调用masksToBounds For further references take a look to How is the relation between UIView's clipsToBounds and CALayer's masksToBounds? 如需进一步参考,请查看UIView的clipsToBounds和CALayer的masksToBounds之间的关系如何? .

This question already has a good answer, but I want to supplement it with some more pictures. 这个问题已经有了一个很好的答案,但我想补充一些更多的图片。 My full answer is here. 我的完整答案就在这里。

To help me remember frame , I think of a picture frame on a wall . 为了帮助我记住框架 ,我想到了墙上的相框 Just like a picture can be moved anywhere on the wall, the coordinate system of a view's frame is the superview. 就像图片可以移动到墙上的任何地方一样,视图框架的坐标系是超视图。 (wall=superview, frame=view) (wall = superview,frame = view)

To help me remember bounds , I think of the bounds of a basketball court . 为了帮助我记住边界 ,我想到了篮球场的界限 The basketball is somewhere within the court just like the coordinate system of the view's bounds is within the view itself. 篮球就在球场内的某个地方,就像视线边界的坐标系在视野内一样。 (court=view, basketball/players=content inside the view) (court = view,basketball / players =视图内容)

Like the frame, view.center is also in the coordinates of the superview. 与框架一样, view.center也在superview的坐标中。

Frame vs Bounds - Example 1 框架与边界 - 示例1

The yellow rectangle represents the view's frame. 黄色矩形表示视图的框架。 The green rectangle represents the view's bounds. 绿色矩形表示视图的边界。 The red dot in both images represents the origin of the frame or bounds within their coordinate systems. 两个图像中的红点表示帧的原点或坐标系内的边界。

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

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

在此输入图像描述


Example 2 例2

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

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

在此输入图像描述


Example 3 例3

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

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

在此输入图像描述


Example 4 例4

This is the same as example 2, except this time the whole content of the view is shown as it would look like if it weren't clipped to the bounds of the view. 这与示例2相同,除了这次显示视图的整个内容,如果它没有被剪切到视图的边界,它将看起来像。

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

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

在此输入图像描述


Example 5 例5

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

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

在此输入图像描述

Again, see here for my answer with more details. 再次,请参阅此处获取更多详细信息的答案。

I found this image most helpful for understanding frame, bounds, etc. 我发现这个图像最有助于理解框架,边界等。

在此输入图像描述

Also please note that frame.size != bounds.size when the image is rotated. 另请注意,旋转图像时frame.size != bounds.size

I think if you think it from the point of CALayer , everything is more clear. 我想如果你从CALayer的角度考虑它,一切都会更清楚。

Frame is not really a distinct property of the view or layer at all, it is a virtual property, computed from the bounds, position( UIView 's center), and transform. Frame根本不是视图或图层的独特属性,它是一个虚拟属性,根据边界,位置( UIView的中心)和变换计算。

So basically how the layer/view layouts is really decided by these three property(and anchorPoint), and either of these three property won't change any other property, like changing transform doesn't change bounds. 所以基本上如何通过这三个属性(和anchorPoint)真正决定图层/视图布局,并且这三个属性中的任何一个都不会更改任何其他属性,例如更改变换不会更改边界。

There are very good answers with detailed explanation to this post. 这篇文章的详细解释有很好的答案。 I just would like to refer that there is another explanation with visual representation for the meaning of Frame, Bounds, Center, Transform, Bounds Origin in WWDC 2011 video Understanding UIKit Rendering starting from @4:22 till 20:10 我只是想提一下,在WWDC 2011视频中,有关于Frame,Bounds,Center,Transform,Bounds Origin的含义的视觉表示的另一种解释,从@ 4:22到20:10开始了解UIKit Rendering

After reading the above answers, here adding my interpretations. 阅读完上述答案后,在此添加我的解释。

Suppose browsing online, web browser is your frame which decides where and how big to show webpage. 假设在线浏览, 网页浏览器是决定显示网页的位置和大小的frame Scroller of browser is your bounds.origin that decides which part of webpage will be shown. 浏览器的滚动条是你的bounds.origin ,决定显示哪个网页部分。 bounds.origin is hard to understand. bounds.origin很难理解。 The best way to learn is creating Single View Application, trying modify these parameters and see how subviews change. 学习的最佳方法是创建单视图应用程序,尝试修改这些参数并查看子视图的更改方式。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM