Search code examples
ioscore-graphicscore-animation

CGRectApplyAffineTransform and actual view's frame


such is the code:

-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
    UIView* view=[[UIView alloc] init];
    CGRect frame=CGRectMake(10, 10, 100, 100);
    view.frame=frame;
    [self.view addSubview:view];
    CGAffineTransform t1 = CGAffineTransformMakeTranslation(0, 100);
    CGAffineTransform t2 = CGAffineTransformMakeScale(.8, .8);
    CGAffineTransform t3 = CGAffineTransformConcat(t1, t2);
    view.transform=t3;
    CGRect rect = CGRectApplyAffineTransform(frame, t3);
    NSLog(@"transform rect:%@", NSStringFromCGRect(rect));
    NSLog(@"transform view rect:%@", NSStringFromCGRect(view.frame));
}
//output:
transform rect:{{8, 88}, {80, 80}}
transform view rect:{{20, 100}, {80, 80}}

a same rect apply a same transform,but get a different rect,that's why?


Solution

  • There is a difference between applying an affine transform on a CGRector UIView object:


    Let's start with CGRectApplyAffineTransform, and look at the description from Apple docs :

    Because affine transforms do not preserve rectangles in general, the function CGRectApplyAffineTransform returns the smallest rectangle that contains the transformed corner points of the rect parameter. If the affine transform t consists solely of scaling and translation operations, then the returned rectangle coincides with the rectangle constructed from the four transformed corners.

    In this case, youth functionapply the transform for each of the point, and returns a CGRectobject contains all these points.

    t(10,10) ->(8,88)
    t(10,110)->(8, 168)
    t(110,10)->(88, 88)
    t(110,110)->(88, 168)
    

    The rect containing all these transformed points is correctly {{8, 88}, {80, 80}}


    Now let's look at the description of the transformproperty from UIView documentation :

    The origin of the transform is the value of the center property, or the layer’s anchorPoint property if it was changed. (Use the layer property to get the underlying Core Animation layer object.) The default value is CGAffineTransformIdentity.

    Since you didn't change the layer's anchor point, the transform is applied from the center of the view.

    The original center is (60,60). The transformed center is (60,140), since the scaling issue doesn't affect the origin point (which is the center). You now have a (80,80) rect centered on (60,140) point : you can find your {{20, 100}, {80, 80}} rectangle.