我想知道如何以正确的方式使用这些属性。
据我了解,frame
可以从我正在创建的视图的容器中使用。
它设置相对于容器视图的视图位置。它还设置了该视图的大小。
也可以从我正在创建的视图的容器中使用center
。此属性更改视图相对于其容器的位置。
最后,bounds
与视图本身相关。它会更改视图的可绘制区域。
您能否提供有关frame
和bounds
之间关系的更多信息?那么clipsToBounds
和masksToBounds
属性呢?
答案 0 :(得分:566)
由于我问过的问题已多次出现,我会详细解答。如果您想添加更多正确的内容,请随意修改它。
首先回顾一下这个问题:框架,边界和中心以及他们之间的关系。
框架视图的frame
(CGRect
)是其superview
坐标系中矩形的位置。默认情况下,它从左上角开始。
Bounds 视图的bounds
(CGRect
)在其自己的坐标系中表示视图矩形。
中心 center
是根据CGPoint
坐标系表示的superview
,它确定了frame.origin = center - (bounds.size / 2.0)
坐标系的确切中心点的位置图。
取自 UIView + position 以上属性中的这些关系(它们在代码中不起作用,因为它们是非正式方程式):
center = frame.origin + (bounds.size / 2.0)
frame.size = bounds.size
frame
注意:如果轮播视图,则这些关系不适用。有关详细信息,我建议您根据 The Kitchen Drawer 课程查看以下来自 Stanford CS193p 的图片。积分归 @Rhubarb 。
使用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)
位于origin
(左上角)。例如,如果您更改view1
的{{1}},则可以看到(如果需要,可以注释前面的代码),现在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
(来源Apple doc)
将此值设置为YES会导致子视图被剪切到边界 接收者如果设置为NO,则其帧超出的子视图 接收器的可见边界不会被剪裁。默认值为 NO。
换句话说,如果视图frame
为(0, 0, 100, 100)
且其子视图为(90, 90, 30, 30)
,则您只会看到该子视图的一部分。后者不会超过父视图的界限。
masksToBounds
相当于clipsToBounds
。而不是UIView
,此属性将应用于CALayer
。在幕后,clipsToBounds
拨打masksToBounds
。如需进一步参考,请查看How is the relation between UIView's clipsToBounds and CALayer's masksToBounds?。
答案 1 :(得分:131)
这个问题已经有了一个很好的答案,但我想补充一些更多的图片。 My full answer is here.
为了帮助我记住框架,我想到墙上的相框。就像图片可以移动到墙上的任何地方一样,视图框架的坐标系是超视图。 (wall = superview,frame = view)
为了帮助我记住界限,我想到了篮球场的界限。篮球就在球场内的某个地方,就像视线边界的坐标系在视野内一样。 (court = view,basketball / players =视图中的内容)
与框架类似, view.center 也位于超级视图的坐标中。
黄色矩形表示视图的框架。绿色矩形表示视图的边界。两个图像中的红点表示帧的原点或坐标系内的边界。
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
再次,请参阅here以获取更多详细信息。
答案 2 :(得分:88)
我发现这个图像对于理解框架,边界等非常有帮助。
请注意图片旋转时frame.size != bounds.size
。
答案 3 :(得分:3)
我认为如果你从CALayer
开始考虑它,一切都会更清楚。
框架根本不是视图或图层的独特属性,它是一个虚拟属性,根据边界,位置(UIView
的中心)和变换计算得出。 强>
基本上如何通过这三个属性(和anchorPoint)真正决定图层/视图布局,并且这三个属性中的任何一个都不会更改任何其他属性,例如更改变换不会更改边界。
答案 4 :(得分:1)
这篇文章的详细解释有很好的答案。我只是想提一下,对于WWDC 2011视频 Understanding UIKit Rendering 中Frame,Bounds,Center,Transform,Bounds Origin的含义的视觉表示有另一种解释,从@ 4:22开始直到20:10
答案 5 :(得分:0)
阅读完上述答案后,在此添加我的解释。
假设在线浏览,网络浏览器是您的frame
,它决定了显示网页的位置和大小。浏览器的 Scroller 是您的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));