preface

Recently in the use of a conversion coordinate system in the code written by a great god, benefit a lot, I studied the transformation of the coordinate system. This time, I will talk with my own understanding.

Coordinate system transformations include four apis, all from UIView.h, that is, these four apis are used for coordinate system transformations for UIView.

- (CGPoint)convertPoint:(CGPoint)point toView:(nullable UIView *)view;
- (CGPoint)convertPoint:(CGPoint)point fromView:(nullable UIView *)view;
- (CGRect)convertRect:(CGRect)rect toView:(nullable UIView *)view;
- (CGRect)convertRect:(CGRect)rect fromView:(nullable UIView *)view;
Copy the code

Actually, it’s not just UIView that has the concept of coordinate system transformation, CALayer has it, but most of our controls inherit from UIView so UIView is used a little bit more

- (CGPoint)convertPoint:(CGPoint)p fromLayer:(nullable CALayer *)l;
- (CGPoint)convertPoint:(CGPoint)p toLayer:(nullable CALayer *)l;
- (CGRect)convertRect:(CGRect)r fromLayer:(nullable CALayer *)l;
- (CGRect)convertRect:(CGRect)r toLayer:(nullable CALayer *)l;
Copy the code

ConvertRect (CGRect)rect toView (nullable UIView *)view; This API, the other three can also be understood.

Practice a

ConvertRect :toView – (CGRect)convertRect:toView: finds the position of the incoming convertRect in the coordinate system of the calling view relative to the incoming toView

I summed up this sentence sounds very abstract, I actually also read some information on the Internet, more abstract feeling ~~~. Let me explain this sentence in three steps. So let’s think about it in terms of the code, and then after that, if you come back to this sentence, it might make a little bit more sense.

  1. The position of the view calling the method relative to the passed toView is used as the origin of the new coordinate system
  2. Based on the new coordinate system, find the convertRect position passed in
  3. Return value: convertRect position relative to toView

Here’s an example:

The following code runs like this

UIView *redView = [[UIView alloc] init]; redView.backgroundColor = [UIColor redColor]; redView.frame = CGRectMake(100, 100, 200, 200); [self.view addSubview:redView]; UIView *greenView = [[UIView alloc] init]; greenView.frame = CGRectMake(50, 50, 100, 100); greenView.backgroundColor = [UIColor greenColor]; [redView addSubview:greenView]; CGRect rect = [redView convertRect:greenView.frame toView:self.view]; NSLog(@"%@", NSStringFromCGRect(rect)); {{150, 150}, {100, 100}}Copy the code

  • Analysis:CGRect rect = [redView convertRect:greenView.frame toView:self.view];
    • Find the position of redView relative to self.view (100, 100) and use (100, 100) as the origin of the new coordinates
    • So greenView.frame is (50, 50, 100, 100), so relative to the new origin, greenview.frame is (50, 50).
    • Return value: position of greenView.frame relative to self.view, i.e. (100 + 50, 100 + 50)

– (CGRect)convertRect: fromView – (CGRect)convertRect: fromView – (CGRect)convertRect: fromView – (CGRect)convertRect: fromView:

FromView is the method call view of the former, and the method caller of the latter is the argument passed in to the toView of the former. So understanding the former, there is no need to remember the latter.

The two apis for Point are similar.

- (CGPoint)convertPoint:(CGPoint)point toView:(nullable UIView *)view;
- (CGPoint)convertPoint:(CGPoint)point fromView:(nullable UIView *)view;
Copy the code

Actual Application Scenarios

There is a practical application business scenario, that is, in Toutiao App, there is an uninterested button on each Cell. Click the uninterested button, and an uninterested view will pop up below the button. At this point, we need to obtain the frame of the uninterested button relative to the whole Window view. So we can set the frame of the uninterested view when we click the uninterested button.

Note: there is a lot on the web that says that toView is passed nil is inaccurate relative to the keyWindow view. If we manually created the keyWindow in the AppDelegate, then nil is passed relative to the keyWindow. If we do not create the keyWindow manually, the keyWindow is empty, so there is no reference to the keyWindow, but to the method caller itself. You can try the effect yourself. The reason for this is probably that the articles on the web are from a few years ago, when applications created using Xcode were created with keyWindow by default. Xcode10, on the other hand, seems to need to create the keyWindow itself.