大佬儿们,我又双叒叕的来了,大家有没有被问到过frame和bounds有什么区别这样的面试题?或者是如何保证Button位置不变,增加点击范围这样的面试题?
什么?没有遇到过!!!哇,如果you know,大佬,大佬,我向你膜拜膜拜,如果you don`t know,那你真的是太幸运了,快来跟我一起揭开frame和bounds若隐若现的面纱吧!
首先,认识一下frame和bounds,两者都是CGRect类型的结构体,包含一个CGPoint(起点)和一个CGSize(尺寸)子结构体,系统的定义如下:
struct CGRect {
CGPoint origin;
CGSize size;
};
origin决定了View的起点,size决定了View的尺寸。
具体使用如下:
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(100, 100, 100, 100);
btn.bounds = CGRectMake(0, 0, 200, 200);
[btn setBackgroundColor:[UIColor blueColor]];
//[btn setImage:[UIImage imageNamed:@"giftBtn_black"] forState:UIControlStateNormal];
//btn.layer.borderWidth = 2.0f;
[btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
[btn setTitle:@"中心点" forState:UIControlStateNormal];
[self.view addSubview:btn];
NSLog(@"\n原始frame:(100, 100, 100, 100),原始bounds:(0, 0, 200, 200),原始center:(150,150)\n输出frame:%@,输出bounds:%@,输出center:%@",NSStringFromCGRect(btn.frame),NSStringFromCGRect(btn.bounds),NSStringFromCGPoint(btn.center));
UIView *centerView = [[UIView alloc] initWithFrame:CGRectMake(148, 148, 4, 4)];
centerView.backgroundColor = [UIColor redColor];
centerView.layer.cornerRadius = 2.0;
centerView.clipsToBounds = YES;
[self.view addSubview:centerView];
设置了不同的属性,产生了不一样的变化,Why?
接着,我们来看下面的一组数据:(先设置frame,后设置bounds)
2020-08-20 16:29:35.173101+0800 FrameAndBoundsDemo[41016:1248335]
原始frame:(100, 100, 100, 100),原始bounds:(0, 0, 100, 100),原始center:(150,150)
输出frame:{{100, 100}, {100, 100}},输出bounds:{{0, 0}, {100, 100}},输出center:{150, 150}
2020-08-20 16:32:50.221082+0800 FrameAndBoundsDemo[41057:1250415]
原始frame:(100, 100, 100, 100),原始bounds:(0, 0, 200, 200),原始center:(150,150)
输出frame:{{50, 50}, {200, 200}},输出bounds:{{0, 0}, {200, 200}},输出center:{150, 150}
2020-08-20 16:34:22.728527+0800 FrameAndBoundsDemo[41072:1251299]
原始frame:(100, 100, 100, 100),原始bounds:(0, 0, 300, 200),原始center:(150,150)
输出frame:{{0, 50}, {300, 200}},输出bounds:{{0, 0}, {300, 200}},输出center:{150, 150}
2020-08-20 16:39:15.104338+0800 FrameAndBoundsDemo[41129:1254300]
原始frame:(100, 100, 100, 100),原始bounds:(100, 100, 100, 100),原始center:(150,150)
输出frame:{{100, 100}, {100, 100}},输出bounds:{{100, 100}, {100, 100}},输出center:{150, 150}
2020-08-20 16:44:32.482065+0800 FrameAndBoundsDemo[41155:1256502]
原始frame:(100, 100, 100, 100),原始bounds:(200, 200, 100, 100),原始center:(150,150)
输出frame:{{100, 100}, {100, 100}},输出bounds:{{200, 200}, {100, 100}},输出center:{150, 150}
2020-08-20 16:45:49.825096+0800 FrameAndBoundsDemo[41173:1257439]
原始frame:(100, 100, 100, 100),原始bounds:(300, 200, 100, 100),原始center:(150,150)
输出frame:{{100, 100}, {100, 100}},输出bounds:{{300, 200}, {100, 100}},输出center:{150, 150}
通过这组数据,你发现了什么?
1、bounds的size(尺寸)改变,会改变frame的origin(起点)和size(尺寸);
2、无论bounds如何改变,View的中心点都不会改变;
3、无论bounds的origin(起点)如何改变,都不会改变frame;(这是不是意味着设置bounds的orgin没有用了?你太天真了,存在即合理,接着往下看)
再来看一个代码示例,只设置A、B、C三个View的frame:
UIView *viewA = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
[viewA setBackgroundColor:[UIColor redColor]];
[self.view addSubview:viewA];
UIView *viewB = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
[viewB setBackgroundColor:[UIColor yellowColor]];
[viewA addSubview:viewB];
UIView *viewC = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
[viewC setBackgroundColor:[UIColor blueColor]];
[viewB addSubview:viewC];
效果如下:
我们可以看出,viewA的父视图是self.view,viewB的父视图是viewA,viewC的父视图是viewB,所以根据位置的展示得出结论:frame是view在父视图坐标系中的起点和大小,以父视图坐标系做为参照点。
接下来,我们把bounds属性也修改一下:
测试一:
viewA.bounds = CGRectMake(50, 50, 200, 200);
viewB.bounds = CGRectMake(50, 50, 200, 200);
viewC.bounds = CGRectMake(50, 50, 200, 200);
测试二:
viewA.bounds = CGRectMake(10, 10, 200, 200);
viewB.bounds = CGRectMake(20, 20, 200, 200);
viewC.bounds = CGRectMake(30, 30, 200, 200);
测试三:
viewA.bounds = CGRectMake(-10, -10, 200, 200);
viewB.bounds = CGRectMake(-20, -20, 200, 200);
viewC.bounds = CGRectMake(-30, -30, 200, 200);
经过三个测试数据,我们来分析一下,
测试一,viewA是以self.view为父视图,父视图的坐标系bounds是(0,0)开始,所以viewA的位置frame在(50,50);viewB是以viewA为父视图,父视图的坐标系bounds是以(50,50)为原点开始的,所以viewB的位置frame(50,50)在坐标系原点,所以viewB和viewA重合了;同理,viewC是以viewB为父视图,父视图的坐标系bounds是以(50,50)为原点开始的,所以viewC的位置frame(50,50)在坐标系原点,所以viewC和viewB重合了。
测试二,测试三,同理测试一的分析,可得出显示的结果,于是,我们可以得出结论:每个视图都有自己的坐标系,且这个坐标系默认以自身的左上角为坐标原点,所有子视图以这个坐标系的原点为基准点。bounds的起点代表的是子视图看待当前视图左上角的位置,bounds的大小代表当前视图的大小。更改bounds中的起点对于当前视图没有影响,只是更改了当前视图的坐标系,对于子视图来说当前视图的左上角已经不再是(0,0), 而是改变后的坐标,坐标系改了,那么所有子视图的位置也会跟着改变。更改bounds的大小,bounds的大小代表当前视图的长和宽,修改长宽后,中心点继续保持不变,长宽进行改变,通过bounds修改长宽看起来就像是以中心点为基准点对长宽两边同时进行缩放。
以上就是对frame和bounds的分析,如果理解的不是很清楚,没关系,你可以这么理解:bounds改变size的大小以frame的中心点向外扩大或缩小是因为,frame确定了view的位置,那么中心点的位置就是固定的,所以即使改变了bounds的大小,还是以frame的中心点,向外扩大或缩小。frame确定位置,bounds改变大小,从而增加点击范围,之后大家可以测试一下改变button的bounds大小,点击范围会不会变大,希望会对你以后的控件开发有所帮助。
好啦,今天就到这里,如果还不理解,那就多读两边,书读百遍,其义自见。该下班了,代码都在上面,所以Demo就不上传Github了,感谢大家。
转载请注明出处,编写不易,且行且珍惜~~~