据我所知,
frame
可以从我正在创建的视图的容器中使用。它将视图的位置相对于容器视图设置,并设置该视图的大小。另外,
center
也可以从我创建的视图的容器中使用。此属性更改视图相对于其容器的位置。最后,
bounds
是相对于视图本身的。它会更改视图的可绘制区域。
您能否提供有关 frame
和 bounds
之间关系的更多信息? clipsToBounds
和 masksToBounds
属性呢?frame
可以从我正在创建的视图的容器中使用。它将视图的位置相对于容器视图设置,并设置该视图的大小。center
也可以从我创建的视图的容器中使用。此属性更改视图相对于其容器的位置。bounds
是相对于视图本身的。它会更改视图的可绘制区域。
您能否提供有关 frame
和 bounds
之间关系的更多信息? clipsToBounds
和 masksToBounds
属性呢?因为我提出的问题已经被许多人看到,所以我将提供一个详细的答案。如果您想添加更多正确的内容,请随意修改。
首先回顾一下问题:frame、bounds和center及其关系。
Frame 一个视图的frame
(CGRect
)是其矩形在superview
坐标系中的位置。默认情况下它从左上角开始。
Bounds 视图的bounds
(CGRect
)表示其自己坐标系统中的视图矩形。
Center 一个center
是一个CGPoint
,以superview
的坐标系表示,并确定视图精确中心点的位置。
从UIView + position中取得这些关系(它们不适用于代码,因为它们是非正式的等式):
frame.origin = center - (bounds.size / 2.0)
center = frame.origin + (bounds.size / 2.0)
frame.size = bounds.size
注意: 如果视图被旋转,这些关系不适用。有关更多信息,建议您查看以下图片,取自The Kitchen Drawer,基于斯坦福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)
(左上角)。例如,如果您更改view1
的origin
,则可以看到(如果您想要注释以前的代码),现在view2
的左上角与view1
的左上角相接。动机非常简单。您告诉view1
其左上角现在位于位置(20.0, 20.0)
,但由于view2
的frame
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
中心的位置。
最后,bounds
和origin
不是相关概念。两者都可以推导出一个视图的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)开始,它们将重合。
其他参考资料(如果需要,可以更新为其他参考资料)
关于clipsToBounds
(源自苹果文档)
将此值设置为YES会导致子视图被剪切到接收器的边界。如果设置为NO,则不剪切其框架超出接收器可见边界的子视图。默认值为NO。
换句话说,如果一个视图的frame
是(0, 0, 100, 100)
,它的子视图是(90, 90, 30, 30)
,你将只看到该子视图的一部分。后者不会超出父视图的边界。
masksToBounds
等同于clipsToBounds
。它是应用于CALayer
的属性,而不是UIView
。在幕后,clipsToBounds
调用masksToBounds
。有关更多资料,请参见UIView的clipsToBounds和CALayer的masksToBounds之间的关系是什么?。
bounds
,因此发表了我的评论。看起来正确的答案是:..+bounds.origin.x。 - user2568508这个问题已经有了一个好的答案,但我想用一些图片来补充它。我的完整回答在这里。
为了帮助我记住frame(框架),我想到挂在墙上的相框。就像一张图片可以移动到墙上的任何地方一样,视图的坐标系是其父视图。(墙=父视图,相框=视图)
为了帮助我记住bounds(范围),我想到篮球场的边界。篮球在球场内的某个位置,就像视图的坐标系在视图本身内部一样。(球场=视图,篮球/球员=视图内部的内容)
与frame类似,view.center也处于父视图的坐标系中。
黄色矩形代表视图的frame。绿色矩形代表视图的bounds。红点在两个图像中表示frame或bounds在它们的坐标系统内的原点。
Frame
origin = (0, 0)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Frame
origin = (40, 60) // That is, x=40 and y=60
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Frame
origin = (20, 52) // These are just rough estimates.
width = 118
height = 187
Bounds
origin = (0, 0)
width = 80
height = 130
这与示例 2 相同,不同之处在于此时视图的整个内容被显示出来,就像它没有被裁剪到视图的边界一样。
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (280, 70)
width = 80
height = 130
此外,有关更详细信息,请参见这里中我提供的答案。
我发现这张图片对于理解框架(frame)、边界(bounds)等很有帮助。
同时请注意,当图像旋转时,frame.size != bounds.size
。
我认为如果你从CALayer
的角度考虑,一切都更加清晰。
实际上,框架(Frame)并不是视图或层的一个独立属性,它是一个虚拟属性,由边界、位置(UIView
的中心)和变换计算而来。
因此,基本上图层/视图的布局是由这三个属性(以及锚点)决定的,而这三个属性中的任何一个都不会改变其他属性,例如改变变换不会改变边界。
这篇文章有很好的回答,并详细解释了其中的内容。我只想提到还有另一种解释,使用可视化图形展示Frame、Bounds、Center、Transform和Bounds Origin的含义。可以在WWDC 2011视频《理解UIKit渲染》中从@4:22开始观看,直至20:10。
frame
,它决定了网页在哪里以及以何种尺寸显示。浏览器的滚动条是你的bounds.origin
,它决定了哪一部分网页将被显示。 bounds.origin
很难理解。学习的最佳方法是创建Single View Application,尝试修改这些参数并观察子视图如何变化。- (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));