首先明确一个问题:frame
, bounds
和 center
是什么及他们之间的关系。
Frame:一个 view
的 frame
是该 view
相对于 superview
坐标系的矩形位置,默认的起始点是左上点。
Bounds: 表示该 view
在自身坐标系的矩形。
Center: 一个 center
是一个 CGPoint
,表示该 view
的中心点相对于 superview
的坐标系的位置。
这几个属性的关系如下:
frame.origin = center - (bounds.size / 2.0)
center = frame.origin + (bounds.size / 2.0)
frame.size = bounds.size
NOTE: 当 view
被旋转后上面的关系不成立。具体参考下面的例子:
frame
可以在 superview
中改变 view
的位置或大小。通常用于 superview
,比如当创建指定 subview
时:
// 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
中画一个 view
通常需要使用 bounds
。典型的例子是在一个 view
中画一个 subview
,此时需要知道 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];
当改变一个 view 的 bounds
时发生不同的行为,比如,如果改变 bounds
的大小,frame
也会改变。这些改变是围绕 view
的 center
发生的(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));
输出如下结果,其中 frame 改变,而 center 没有改变:
Old Frame {{20, 20}, {360, 360}}
Old Center {200, 200}
New Frame {{10, 10}, {380, 380}}
New Center {200, 200}
此外,如果改变 bounds
的原点,就会改变内部坐标系的原点。默认的原点是 (0.0, 0.0)
。比如,改变 view1
的原点,会发现 view2
的左上点与 view1
的左上点重合了,这个变化是显而易见的。
CGRect frame = view1.bounds;
frame.origin.x += 20.0f;
frame.origin.y += 20.0f;
view1.bounds = frame;
原点不仅表示 view
相对于 superview
的位置,也描述了 bounds
中心的位置。
最后,bounds
和 origin
不是同一个概念,他们都影响 view
的 frame
。
示例代码:
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]
的 bounds
// 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
的 frame
原点开始于 (30.0, 20.0)
,他们是一致的。
Additional references
关于 clipsToBounds
,Apple
的文档如下:
Setting this value to YES causes subviews to be clipped to the bounds of the receiver. If set to NO, subviews whose frames extend beyond the visible bounds of the receiver are not clipped. The default value is NO.
换句话说,如果一个 view
的 frame
是 (0, 0, 100, 100)
,而 subview
是 (90, 90, 30, 30)
,就只能看到 subview
的一部分。超过 parent view
的 bounds
的部分不会显示。
masksToBounds
等于 clipsToBounds
,不同于 clipsToBounds
用于 UIView
, masksToBounds
属性应用于 CALayer
。 实际上,clipsToBounds
调用 masksToBounds
。
更多可以参考How is the relation between UIView's clipsToBounds and CALayer's masksToBounds?。
网友评论