19

CGRect A と CGRect B の 2 つの CGRect があるとします。私の UIView のフレームは CGRect B と同じですが、フレーム A から B に移行する UIView を示すアニメーションを作成したいと考えています。

UIView の transform プロパティを変更することでこれを実行しようとしているので、そのフレームをあまりいじる必要はありません。ただし、これを可能にするには CGAffineTransform が必要です。この変換を計算する最良の方法は何ですか?

4

6 に答える 6

43

以前の答えは私にはうまくいきませんでした。これはうまくいくはずです:

Swift 5 (拡張)

extension CGAffineTransform {
    init(from source: CGRect, to destination: CGRect) {
        let t = CGAffineTransform.identity
            .translatedBy(x: destination.midX - source.midX, y: destination.midY - source.midY)
            .scaledBy(x: destination.width / source.width, y: destination.height / source.height)
        self.init(a: t.a, b: t.b, c: t.c, d: t.d, tx: t.tx, ty: t.ty)
    }
}

スイフト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)
}

迅速

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

Objective-C

+ (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;
}
于 2015-01-29T12:03:20.010 に答える
8

私はこれに便利な方法を見つけることができなかったので、これを達成するために試行錯誤した真の行列計算に頼りました。

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);
于 2012-05-29T15:49:49.683 に答える
3

これは、縦横比も考慮したjosema.vitaminewの回答のバリエーションです(ビデオや画像を扱う場合に役立ちます):

+ (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;
}
于 2016-04-11T01:51:45.400 に答える
3

素敵な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)
    }
}
于 2017-05-13T20:41:23.307 に答える
1

上記のコード スニペットの最後の行は、次のように変更する必要があります。

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

于 2014-10-11T12:52:55.837 に答える
0

カノビウスの回答を使い始めましたが、彼の「アスペクト比」という用語の使用を誤解しているか、期待どおりに機能しなかったために誤解しています。これは、元のビューのアスペクト比を維持して (H と W の両方にスケーリングを適用することにより)、「アスペクト フィット」動作を実現する私のバージョンです。

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

    // since the scale transform works around the midpoints, align them before doing the transform.
    transform = CGAffineTransformTranslate(transform, -(CGRectGetMidX(sourceRect)-CGRectGetMidX(finalRect)), -(CGRectGetMidY(sourceRect)-CGRectGetMidY(finalRect)));

    CGFloat originalHeight = sourceRect.size.height;
    CGFloat scaledHeight = finalRect.size.height;
    CGFloat hScalePercentage = scaledHeight / originalHeight;

    CGFloat originalWidth = sourceRect.size.width;
    CGFloat scaledWidth = finalRect.size.width;
    CGFloat wScalePercentage = scaledWidth / originalWidth;

    if (keepingAspectRatio)  
    {
        CGFloat scalePercentage = MIN(hScalePercentage, wScalePercentage);   // the most amount of scaling == smallest float number
        transform =  CGAffineTransformScale(transform, scalePercentage, scalePercentage);
    }
    else
    {
        transform = CGAffineTransformScale(transform, wScalePercentage, hScalePercentage);
    }

    return transform;
}
于 2020-02-28T01:10:34.623 に答える