浅析frame与bounds

UIView 有两个属性,frame 与 bounds。我们所熟知的是 bounds 其实就是 x,y 均为0的 frame。但是你是否有过这样的疑问:

  • 既然 bounds 就是 x,y 均为0的 frame,那为什么还要有 bounds 这个属性的存在,直接使用 frame 不就好了么。
  • 既然 bounds 的 x,y,均为0,那为什么 bounds 还是 CGRect 类型,直接是 CGSize 类型不就好了么。

针对问题一,我们给出的答案是,frame 是描述当前 view 相对于父 view 的坐标系的位置关系,而 bounds 是描述当前 view 相对于自己的坐标系的位置关系。这两个属性所描述的东西不同所以都有存在的意义,而且这也很好的解释了为什么 bounds 的 x,y 值始终为0。

那么对于为题二,既然 bounds 是 CGRect 类型的,那么就表示其 x,y 属性都是有意义的。那么我们就来看一下 bounds 的 x,y 属性的意义究竟是什么

测试 bounds 的 x,y 属性

代码一

UIView *superView = [[UIView alloc]initWithFrame:CGRectMake(50, 50, 200, 200)];
superView.backgroundColor = [UIColor redColor];
superView.clipsToBounds = YES;
[self.view addSubview:superView];

UIView *view1 = [[UIView alloc]initWithFrame:CGRectMake(5, 5, 100, 100)];
view1.backgroundColor = [UIColor blueColor];
[superView addSubview:view1];

代码一效果图

这是默认代码的样式,红色为 superView 蓝色为 view1

接下来我们试着修改一下 bounds 的 y 值

代码二

UIView *superView = [[UIView alloc]initWithFrame:CGRectMake(50, 50, 200, 200)];
superView.backgroundColor = [UIColor redColor];
superView.clipsToBounds = YES;
[self.view addSubview:superView];

UIView *view1 = [[UIView alloc]initWithFrame:CGRectMake(5, 5, 100, 100)];
view1.backgroundColor = [UIColor blueColor];
[superView addSubview:view1];

CGRect superBounds = superView.bounds;
superBounds.origin.y = 50;
superView.bounds = superBounds;

代码二效果图

在代码二中,我们改变了 superView 的 bounds.origin.y 可见 view1 的位置改变了,view1似乎是向上平移了bounds.origin.y。

说明

前面我们说过 bounds 实际是view相对于自己坐标系的位置关系,因此当我们修改 bounds 的 y 值的时候实际上就是view相对于自己坐标系下移了50px,但是 view 相对于父坐标系的位置是由 frame 指定的,这里frame 并没有变,所以 view 相对于服坐标系的位置病不会改变,所以也就是view的坐标系上移了50。由于坐标系的变化,也就导致了起内部的 subviews 的坐标值全部改变了。

在这个例子中也就是我们改变了红色 view 的 bounds.origin.y=50 ,但是我们并没有改变红色 view 的 frame,所以红色 view 相对于黄色 view 的位置并不会发生改变,但是还要让红色 view 相对于自己坐标系下移50,所以只能是红色 view 的坐标轴上移50了。由于红色 view 的坐标轴位置改变,导致了起内部所有 subview 的位置改变,也就使得蓝色 view 的位置上移了50。

总结

实际上 bounds 属性与 frame 属性所描述的东西是不同的,bounds 属性描述相对于自身坐标系的位置关系,其中的 x,y 值在一般情况下均为0,但是我们可以通过修改 x,y 的值来修改坐标轴的位置,从而影响到其内部所有子 view 的位置。这里需要注意的是,bounds.origin.x>0 表示坐标轴左移,对应的内部子 view 左移,bounds.origin.y>0 表示坐标轴上移,对应的内部子 view 上移。

参考

UIView.frame的骗局