iOS DeveloperiOS学习专题

秒懂frame和bounds, 从此以后不迷惑

2016-08-25  本文已影响213人  bigParis

我们在写bounds的时候通常是self.xxxView.bounds = CGRectMake(0,0,100,100);似乎(x, y)写成(0, 0)是一种习惯, 也是一种比较安全的行为, 因为, 如果改变了(x, y)通常会有无法预知的事情发生, 今天就来探索下, 到底会发生些什么!

1 frame基本用法

    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = UIColor.redColor;
    redView.frame = CGRectMake(0, 0, 200, 200);
    [self.view addSubview:redView];
图1

没有什么好说的, 大家都知道结果会是这样

2初级用法

    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = UIColor.redColor;
    redView.bounds = CGRectMake(0, 0, 200, 200);
    [self.view addSubview:redView];
图2

看到了吗? 在不设置frame的情况下, 只设置bounds, 会让redView的中心点和self.view的起始点重合, 这里不得不说一下锚点:

一个view的layer是有anchorPoint的, 默认情况下, anchorPoint是(0.5, 0.5), 也就是在这个view的中点. 当addSubview(如果仅仅设置了bounds)的时候, 会让锚点和父view的起始点重合, 这也就解释了为什么会出现图2的情况. 我想对于单独使用bounds出现的结果, 我已经解释清楚了.

3中级用法

    [super viewDidLoad];
    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = UIColor.redColor;
    redView.frame = CGRectMake(0, 0, 200, 200);
    redView.bounds = CGRectMake(-100, -100, 200, 200);
    [self.view addSubview:redView];
    
    UIView *blueView = [[UIView alloc] init];
    blueView.backgroundColor = UIColor.blueColor;
    blueView.frame = CGRectMake(0, 0, 100, 100);
    [redView addSubview:blueView];

这里已经把redView 的frame设置在了(0,0,200,200) 然后又设置了bounds, 但是不改变width和height

图3

这种情况, (-100, -100) 相当于把redView的坐标系, 也就是redView的子view(这里就是blueView了)的起始点向右下移动(100, 100), 这里的减号表示方向, point的第一个参数是左右移动, 第二个是上下移动, so, 此时蓝色view认为父view(红色view)的起始点在整个坐标系的(100, 100)位置. 所以此时设置蓝色view的frame会出现在图3的位置.

4高级用法

    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = UIColor.redColor;
    redView.frame = CGRectMake(0, 0, 200, 200);
    redView.bounds = CGRectMake(-100, -100, 300, 300);
    [self.view addSubview:redView];

此时通过给redView设置bounds, 不仅改变(x, y)还改变(width, height)这时候会出现什么结果呢?

图4

输出一下redView的frame

{{-50, -50}, {300, 300}}

起始点变成了(-50, -50)
输出下anchorPoint

{0.5, 0.5}

锚点没变, 但是起点变了. 说好的anchorPoint和起点重合呢? 喂, 现在不是单纯的设置bounds啊, 你设置了frame了好不啦! 为什么会出现这种情况呢? 小编认为, 在单纯通过设置bounds的情况下, 锚点的绝对坐标应该是{0, 0}, 但是现在先设置了frame又重置了bounds的宽高(注意, 这里bounds的x,y不会影响到redView的显示), 那增加的宽高如何分配呢? 总之宽高都不能变, 还是{300, 300}, 那就确定锚点的绝对坐标就行了, 锚点最初因为设置frame(0,0,200, 200), 所以锚点的绝对坐标在{100, 100}, 因为锚点的绝对坐标是不会变的, 所以frame的范围是{100-300/2, 100+300/2}={-50,250}, 所以frame={{-50, -50}, {300, 300}}

5终极玩法

    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = UIColor.redColor;
    redView.frame = CGRectMake(20, 20, 200, 200);
    redView.bounds = CGRectMake(0, 0, 300, 300);
    [self.view addSubview:redView];

如果说高级玩法还勉强可以接受的话, 那终极玩法纯粹是作死啊, 已经设置了frame, 然而frame并不在整个view的起点, 因为锚点(0.5, 0.5), 通过frame确定中心点, 为(120, 120), 因为锚点不动, 所以frame的范围是{120-150, 120+150}, 所以frame={{-30, -30}, {300, 300}}
看下结果

图5

总结:

1 设置了bounds的(x, y)相当于给子view一个起点, 其中, 减号表示向正方向偏移.
2 单纯设置bounds显示出来的view的位置和锚点有关.
3 通过先设置frame再设置bounds的做法在实际开发中没任何意义. 要知道真实frame的绝对位置, 需要通过锚点确定的原中心点的绝对位置, 然后保持中心点位置不变, 根据大小就能确定起始点了.
4 先设置bounds再设置frame, 以frame值为最终view的frame.

思考

    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = UIColor.redColor;
    redView.frame = CGRectMake(20, 20, 200, 200);
    redView.bounds = CGRectMake(0, 0, 100, 100);
    [self.view addSubview:redView];

这个redView的frame是多少呢?

答案:

{{70, 70}, {100, 100}}

解读:

frame(20, 20, 200, 200)和anchorPoint(0.5, 0.5), 确定了中心点的绝对位置 20+200*0.5 = 120, 因为锚点不动, 所以frame的范围是{120-50, 120+50}, 所以frame={{70, 70}, {100, 100}}.

上一篇下一篇

猜你喜欢

热点阅读