我们在写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];
没有什么好说的, 大家都知道结果会是这样
2初级用法
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = UIColor.redColor;
redView.bounds = CGRectMake(0, 0, 200, 200);
[self.view addSubview:redView];
看到了吗? 在不设置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
这种情况, (-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)
这时候会出现什么结果呢?
输出一下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}}
看下结果
总结:
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}}
.