层次结构: 一图胜万言。

[whiteView addSubView:redView];
[yellowView addSubView:self.view];
[redView addSubView:self.view];
(注:黑的View
可以先不予理会,用来标记最后获取到位置的显示)
需求:
将whiteView
转换到self.view
坐标系中对应的frame
;
CGRect rect1 = [self.whiteview convertRect:self.whiteview.frame toView:self.yellowview];
NSLog(@"rect1 : %@",NSStringFromCGRect(rect1));
CGRect rect2 = [self.yellowview convertRect:rect1 toView:self.yellowview.superview];
NSLog(@"rect1 : %@",NSStringFromCGRect(rect2));
输出:
yellowview.frame : {{37, 20}, {200, 200}}
redview.frame : {{37, 20}, {200, 200}}
whiteview.frame : {{40, 40}, {50, 50}}
rect1 : {{80, 80}, {50, 50}}
rect2 : {{117, 100}, {50, 50}}
- 根据上面的代码
- 第一次将
whiteView
转换到yellowView
上获取的Rect :rect1 : {{80, 80}, {50, 50}}
可以看到x,y 的坐标明显增加了一倍。- 第二次将转换到
yellowView
上的rect1转换到self.view
上获取的Rect :rect2 : {{117, 100}, {50, 50}}
(最终得到的位置)。
下面用黑色的View
来移动到最终的位置rect2 : {{117, 100}, {50, 50}}

为什么 rect2.origin.x = 117, rect2.origin.y = 100?
rect2.origin.x = 37 + 80;
// 20 是状态栏的高度
rect2.origin.y = 20 + 80;
看到这里,这好像不是我们想要的结果。无论如何在第一次转换时x
,y
坐标不应该被放大一倍。
我在看一些第三方库的时候,看见有人这么去写,解决方法是,将x
,y
,在用到计算时将其强行减去增加的部分,x-=40
, y-=40
; 似乎好像也没什么问题。在我理解这样的做法就是将错就错。
那么问题出现在什么地方,该如何解决?
我们可以猜测convertRect:toView:
这个方法究竟做了什么?该如何使用?苹果官方对这个方法的解释是这样的。

直译过来是这样的
摘要
将矩形从接收器的坐标系转换为另一个视图的矩形。
宣言
- (CGRect)convertRect:(CGRect)rect toView:(UIView *)view;
参数
矩形
在接收器的本地坐标系(边界)中指定的矩形。
视图
作为转换操作目标的视图。 如果view为nil,则此方法将转换为窗口基坐标。 否则,视图和接收器都必须属于同一个UIWindow对象。
调用者(接收器的坐标系):谁来调用这个方法,(以矩形所在的坐>标系的视图去调用)。
矩形:需要转换的Rect。
目标视图:需要转换到的目标视图。
总结:
frame 的坐标系是相对于父视图的(对应的由父视图调用)
bounds 的坐标系是相对于本身的(对应的由自身去调用)
举个🌰
CGRect rect3 = [self.redview.superview convertRect:self.redview.frame toView:self.view];
NSLog(@"rect3 : %@",NSStringFromCGRect(rect3));
/**
1. self.redview.superview --> 子控件的self.redview.frame(正确✅)
self.redview.frame 的坐标系是其父视图(如果此时的rect:self.redview.bounds,其坐标就是{{0, 0}, {200, 200}}这样的。那么就是以自身为参考系,导致转换并不是我们想要的)
2. self.redview --> self.redview.frame = bounds(正确✅)
因为x和y为0 就是原点坐标此时rect所在的坐标系视图就是self.redview(自身)
3. CGRect rect3 = [self.redview convertRect:self.redview.frame toView:self.view];(错误❎)
对于这种错误的写法,应该分两种情况考虑:
如果frame的{x,y}的坐标不为0,那么参考的坐标系是父视图,应该是由父视图调用
如果frame的{x,y}的坐标为0,那么参参考系的坐标是自身,应该由自身调用
总结:frame 的坐标系是相对于父视图的(对应的由父视图调用)
bounds 的坐标系是相对于本身的(对应的由自身去调用)
*/
上面出错的原因是并不是以frame
所在的坐标系的视图去调用该转换方法,(而是用其本身去调用导致出错[self.whiteview convertRect:self.whiteview.frame toView:self.yellowview];
)
正确的调用应该是这样的
CGRect newrect = [self.redview convertRect:self.whiteview.frame toView:self.yellowview];
其他代码不用修改。
CGRect rect1 = [self.redview convertRect:self.whiteview.frame toView:self.yellowview];
NSLog(@"rect1 : %@",NSStringFromCGRect(rect1));
CGRect rect2 = [self.yellowview convertRect:rect1 toView:self.yellowview.superview];
NSLog(@"rect2 : %@",NSStringFromCGRect(rect2));
输出
yellowview.frame : {{37, 20}, {200, 200}}
redview.frame : {{37, 20}, {200, 200}}
whiteview.frame : {{40, 40}, {50, 50}}
rect1 : {{40, 40}, {50, 50}}
rect2 : {{77, 60}, {50, 50}}
总结:
convertRect:toView:
convertRect:fromView:
这两方法在开发中是经常使用的,使用得当,可以用来做一些很好的功能。两个方法的作用是一样的,由上所述,在也不会对这两个方法迷糊了。
示例Demo
网友评论