UIView框架,边界和中心
我想知道如何以正确的方式使用这些属性。
据我所知, frame
可以从我创建的视图的容器中使用。 它设置相对于容器视图的视图位置。 它还设置了该视图的大小。
也可以从我创建的视图的容器中使用center
。 该属性更改视图相对于其容器的位置。
最后, bounds
是相对于视图本身。 它改变了可视区域的视图。
你能给更多关于frame
和bounds
之间的关系的信息吗? clipsToBounds
和masksToBounds
属性怎么样?
由于我问了很多次的问题,我会提供一个详细的答案。 如果你想添加更多正确的内容,随意修改它。
首先回顾一下这个问题:框架,界限,中心和他们的关系。
框架视图的frame
( CGRect
)是其矩形在超superview
坐标系中的位置。 默认情况下,它从左上角开始。
边界视图bounds
( CGRect
)在其自己的坐标系中表示一个视图矩形。
中心 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)
(左上角)。 例如,如果您更改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)开始,它们将重合。
额外的参考 (如果你想要更新与其他参考)
- 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));