美文网首页iOS 奇闻轶事
iOS如何正确使用convertRect:toView:

iOS如何正确使用convertRect:toView:

作者: Mr_DML | 来源:发表于2018-11-06 23:46 被阅读0次

层次结构: 一图胜万言。

Snip20181106_9.png
[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}}
  • 根据上面的代码
  1. 第一次将whiteView转换到yellowView上获取的Rect :rect1 : {{80, 80}, {50, 50}}可以看到x,y 的坐标明显增加了一倍。
  2. 第二次将转换到yellowView上的rect1转换到self.view上获取的Rect :rect2 : {{117, 100}, {50, 50}}(最终得到的位置)。
    下面用黑色的View来移动到最终的位置rect2 : {{117, 100}, {50, 50}}
[图片上传中...(Snip20181106_13.png-c9963-1541514840615-0)]

为什么 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:这个方法究竟做了什么?该如何使用?苹果官方对这个方法的解释是这样的。

Snip20181106_16.png
直译过来是这样的
  摘要
     
     将矩形从接收器的坐标系转换为另一个视图的矩形。
     宣言
     
     - (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

相关文章

网友评论

    本文标题:iOS如何正确使用convertRect:toView:

    本文链接:https://www.haomeiwen.com/subject/reupxqtx.html