0

ピンチ/ズームを同時に行うジェスチャを作成する方法を示す Stanford Uni Lectures / WWDC ビデオをいじってみました。CGAffineTransformUIView に適用する を返します。

これはすべて正常に動作しますが、もう少し流動的にして、コードに減速を追加しようとしています。UIGestureRecognizerStateChanged各呼び出しで変換マトリックスを保存することでこれを実行しようとしました。受信UIGestureRecognizerStateEndedすると、最後の Changed マトリックスと Ended マトリックスの間のデルタを保存します。

- (void)handleTransform:(TransformGestureRecognizer *)transformRecognizer
{
    CGAffineTransform transform = transformRecognizer.transform;

    // cancel any previous animation updates
    [UIView cancelPreviousPerformRequestsWithTarget:self selector:@selector(decelerateView:) object:transformRecognizer.view];

    if(transformRecognizer.state == UIGestureRecognizerStateBegan)
    {
        transform = CGAffineTransformConcat(transformRecognizer.view.transform, transform);
        transformRecognizer.transform = transform;
    }
    else if(transformRecognizer.state == UIGestureRecognizerStateChanged)
    {
        changingTransform = transform;
    }
    else if(transformRecognizer.state == UIGestureRecognizerStateEnded)
    {
        // get transform difference
        releaseTransformDiff.a = (transform.a - changingTransform.a);
        releaseTransformDiff.b = (transform.b - changingTransform.b);
        releaseTransformDiff.c = (transform.c - changingTransform.c);
        releaseTransformDiff.d = (transform.d - changingTransform.d);
        releaseTransformDiff.tx = (transform.tx - changingTransform.tx);
        releaseTransformDiff.ty = (transform.ty - changingTransform.ty);

        // start updating deceleration animation
        [self performSelector:@selector(decelerateView:) withObject:transformRecognizer.view afterDelay:1.0/60.0];
    }

    transformRecognizer.view.transform = transform;
}

次に、decelerateView:減速をアニメーション化する方法があります。

#define DECELERATION_RATE 0.9

- (void)decelerateView:(UIView *)view
{
    releaseTransformDiff.a = releaseTransformDiff.a * DECELERATION_RATE;
    releaseTransformDiff.b = releaseTransformDiff.b * DECELERATION_RATE;
    releaseTransformDiff.c = releaseTransformDiff.c * DECELERATION_RATE;
    releaseTransformDiff.d = releaseTransformDiff.d * DECELERATION_RATE;
    releaseTransformDiff.tx = releaseTransformDiff.tx * DECELERATION_RATE;
    releaseTransformDiff.ty = releaseTransformDiff.ty * DECELERATION_RATE;

    view.transform = CGAffineTransformMake(view.transform.a + releaseTransformDiff.a, 
                                           view.transform.b + releaseTransformDiff.b, 
                                           view.transform.c + releaseTransformDiff.c, 
                                           view.transform.d + releaseTransformDiff.d, 
                                           view.transform.tx + releaseTransformDiff.tx,
                                           view.transform.ty + releaseTransformDiff.ty);
    [self performSelector:@selector(decelerateView:) withObject:view afterDelay:1.0/60.0];
}

これは時々機能しますが、突然停止し、実際に回転スピンを減速させることはありません.2つのマトリックスのデルタを正しく計算していないと思います. これを行う正しい方法は何ですか?

4

1 に答える 1

1

CGAffineTransformation は、3 x 3 行列を表す簡略化されたデータ構造です。

|a  b  0|
|c  d  0|
|tx ty 1|

点は、3 x 1 行列に上記の行列を掛けることによって変換されます。

                      |a  b  0|
[x' y' 1] = [x y 1] X |c  d  0|
                      |tx ty 1|

スケーリング アフィン変換を作成するには、a を x 軸をスケーリングする係数に設定し、d を y 軸をスケーリングする係数に設定します。平行移動アフィン変換を作成するには、tx を x 軸に沿って移動する値に設定し、ty を y 軸に沿って移動する値に設定します。

この質問で使用される手法は、単にスケーリングまたは並進変換 (またはこれら 2 種類の変換の組み合わせ) であるアフィン変換に有効です。これは、影響を受ける 4 つの値が線形かつ独立して変化するためです。

角度 A の回転アフィン変換を作成するには、a を cos A に、b を sin A に、c を -sin A に、d を cos A に設定します。sin と cos は線形関数ではないため、質問で提案されているデルタ変更は次のようになります。正しく動作しません。さらに複雑なことに、2 つの変換の組み合わせは、それらの変換を表す 2 つの行列の乗算です。回転が含まれている場合、結果の行列は、わずかに異なる変換になる行列と直線的に異なることはありません。

デルタ変換を構築する方法は、入力を変換構築関数呼び出しに変更することであり、結果の行列を直接操作することではありません。

于 2012-05-08T18:45:36.617 に答える