Is there a way to calculate the CGAffineTransform needed to transform a view from frame A to frame B?

The previous answers didn't work for me. This should work:

+ (CGAffineTransform) transformFromRect:(CGRect)sourceRect toRect:(CGRect)finalRect {
    CGAffineTransform transform = CGAffineTransformIdentity;
    transform = CGAffineTransformTranslate(transform, -(CGRectGetMidX(sourceRect)-CGRectGetMidX(finalRect)), -(CGRectGetMidY(sourceRect)-CGRectGetMidY(finalRect)));
    transform = CGAffineTransformScale(transform, finalRect.size.width/sourceRect.size.width, finalRect.size.height/sourceRect.size.height);

    return transform;
}

Swift:

func transformFromRect(from: CGRect, toRect to: CGRect) -> CGAffineTransform {
    let transform = CGAffineTransformMakeTranslation(CGRectGetMidX(to)-CGRectGetMidX(from), CGRectGetMidY(to)-CGRectGetMidY(from))
    return CGAffineTransformScale(transform, to.width/from.width, to.height/from.height)
}

Swift 4:

func transformFromRect(from source: CGRect, toRect destination: CGRect) -> CGAffineTransform {
    return CGAffineTransform.identity
        .translatedBy(x: destination.midX - source.midX, y: destination.midY - source.midY)
        .scaledBy(x: destination.width / source.width, y: destination.height / source.height)
}

I haven't been able to find a convenience method of any kind for this, so I resorted to tried and true matrix calculations to achieve this.

Given a CGRect A and CGRect B, to calculate the transformation needed to go from A to B, do the following:

CGAffineTransform transform = CGAffineTransformTranslate(CGAffineTransformIdentity, -A.origin.x, -A.origin.y);
transform = CGAffineTransformScale(transform, 1/A.size.width, 1/A.size.height);
transform = CGAffineTransformScale(transform, B.size.width, B.size.height);
transform = CGAffineTransformTranslate(transform, B.origin.x, B.origin.y);

Here's a variation on josema.vitaminew answer that also considers aspect ratio (useful if you are working with videos or images):

+ (CGAffineTransform)transformFromRect:(CGRect)sourceRect toRect:(CGRect)finalRect keepingAspectRatio:(BOOL)keepingAspectRatio {
    CGAffineTransform transform = CGAffineTransformIdentity;

    transform = CGAffineTransformTranslate(transform, -(CGRectGetMidX(sourceRect)-CGRectGetMidX(finalRect)), -(CGRectGetMidY(sourceRect)-CGRectGetMidY(finalRect)));

    if (keepingAspectRatio) {
        CGFloat sourceAspectRatio = sourceRect.size.width/sourceRect.size.height;
        CGFloat finalAspectRatio = finalRect.size.width/finalRect.size.height;

        if (sourceAspectRatio > finalAspectRatio) {
            transform = CGAffineTransformScale(transform, finalRect.size.height/sourceRect.size.height, finalRect.size.height/sourceRect.size.height);
        } else {
            transform = CGAffineTransformScale(transform, finalRect.size.width/sourceRect.size.width, finalRect.size.width/sourceRect.size.width);
        }
    } else {
        transform = CGAffineTransformScale(transform, finalRect.size.width/sourceRect.size.width, finalRect.size.height/sourceRect.size.height);
    }

    return transform;
}