Есть ли способ вычислить CGAffineTransform, необходимый для преобразования вида из кадра A в кадр B?

Скажем, у меня есть два CGR, CGRect A и CGRect B. Мой кадр UIView совпадает с CGRect B, но я хочу создать анимацию, показывающую переход UIView из кадра A в B.

Я пытаюсь сделать это, изменив свойство преобразования UIView, поэтому мне не нужно слишком много обходиться со своим фреймом. Тем не менее, мне нужен CGAffineTransform, чтобы сделать это возможным. Каков наилучший способ вычисления этого преобразования?

Ответ 1

Я не смог найти для вас какой-либо удобный метод, поэтому для достижения этого я прибегал к проверенным и истинным вычислениям.

Для CGRect A и CGRect B для вычисления преобразования, необходимого для перехода от A к B, выполните следующие действия:

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);

Ответ 2

Предыдущие ответы не сработали для меня. Это должно работать:

+ (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)
}

Ответ 3

Здесь вариант josema.vitaminew answer, который также учитывает соотношение сторон (полезно, если вы работаете с видео или изображениями):

+ (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;
}

Ответ 4

Хорошее решение Swift 3:

extension CGAffineTransform {
    init(from: CGRect, toRect to: CGRect) {
        self.init(translationX: to.midX-from.midX, y: to.midY-from.midY)
        self = self.scaledBy(x: to.width/from.width, y: to.height/from.height)
    }
}

Ответ 5

Последняя строка в приведенном выше фрагменте кода должна быть изменена следующим образом:

transform = CGAffineTransformTranslate (transform, B.origin.x*A.size.width/B.size.width, B.origin.y*A.size.height/B.size.height);