首页 文章

UIView框架,边界和中心

提问于
浏览
303

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

据我所知, frame 可以从我正在创建的视图的容器中使用 . 它设置相对于容器视图的视图位置 . 它还设置该视图的大小 .

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

最后, bounds 与视图本身相关 . 它会更改视图的可绘制区域 .

你能否提供更多关于 framebounds 之间关系的信息? clipsToBoundsmasksToBounds 属性怎么样?

6 回答

  • 1

    我想如果你从 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.

    所以基本上如何通过这三个属性(和anchorPoint)真正决定图层/视图布局,并且这三个属性中的任何一个都不会更改任何其他属性,例如更改变换不会更改边界 .

  • 87

    这篇文章的详细解释有很好的答案 . 我只是想提一下,在WWDC 2011视频 Understanding UIKit Rendering 从@ 4:22到20:10开始,有关于Frame,Bounds,Center,Transform,Bounds Origin的含义的视觉表示的另一种解释

  • 561

    由于我问过的问题已多次出现,我将提供详细的答案 . 如果您想添加更多正确的内容,请随意修改它 .

    首先回顾一下这个问题:框架,界限和中心以及他们之间的关系 .

    Frame 视图的 frameCGRect )是其矩形在 superview 坐标系中的位置 . 默认情况下,它从左上角开始 .

    Bounds 视图的 boundsCGRect )在其自己的坐标系中表示视图矩形 .

    Center A centerCGPoint ,以 superview 的坐标系表示,它确定了视图精确中心点的位置 .

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

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

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

    • frame.size = bounds.size

    NOTE: 如果轮换视图,则这些关系不适用 . 有关详细信息,我建议您根据 Stanford CS193p 课程查看从 The Kitchen Drawer 拍摄的以下图像 . 积分转到 @Rhubarb .

    Frame, bounds and center

    使用 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 . 一个典型的例子可能是在第一个插图中插入一个子视图 . 绘制子视图需要知道superview的 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 for view1 ,您可以看到(如果需要,请注释前面的代码),现在 view2 的左上角触及了 view1 . 动机很简单 . 你对 view1 说它的左上角现在位于 (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;
    

    origin 表示 viewsuperview 中的位置,但描述了 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)开始,它们将重合 .

    Additional references (如果需要,可以使用其他参考资料更新)

    关于 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? .

  • 126

    这个问题已经有了一个很好的答案,但我想补充一些更多的图片 . My full answer is here.

    为了帮助我记住 frame ,我想起了 a picture frame on a wall . 就像图片可以移动到墙上的任何地方一样,视图框架的坐标系是超视图 . (wall = superview,frame = view)

    为了帮助我记住 bounds ,我想起了 the bounds of a basketball court . 篮球就在球场内的某个地方,就像视线边界的坐标系在视野内一样 . (法庭=视图,篮球/球员=视图内的内容)

    像框架一样, view.center 也在superview的坐标中 .

    框架与边界 - 示例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

    再次,请参阅here以获取更多详细信息 .

  • 3

    我发现这个图像对于理解框架,边界等最有帮助 .

    enter image description here

    另请注意图像旋转时的 frame.size != bounds.size .

  • 0

    阅读完上述答案后,在此添加我的解释 .

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

相关问题