web-dev-qa-db-ja.com

UIViewアニメーションが最初にジャンプする

私はこのコードを実行しています...

[UIView animateWithDuration:0.2
                      delay:0.0
                    options:UIViewAnimationOptionCurveEaseOut
                 animations:^{

                     CGAffineTransform settingsTransform = CGAffineTransformMakeTranslation(self.settingsView.frame.size.width, 0);
                     CGAffineTransform speedTransform = CGAffineTransformMakeTranslation(-self.speedView.frame.size.width, 0);

                     self.settingsView.transform = settingsTransform;
                     self.speedView.transform = speedTransform;

                 } completion:nil];

しかし、ビューを実行すると、正しい方向に半分の位置にスライドする前に、ビューが変換の半分を反対方向にジャンプします。

アニメーションの持続時間を5秒に落としましたが、最初のジャンプは瞬間的で、変換の半分が間違った方向に行われました。

このコードを使用してアニメーションを戻すと...

[UIView animateWithDuration:0.2
                      delay:0.0
                    options:UIViewAnimationOptionCurveEaseOut
                 animations:^{
                     self.settingsView.transform = CGAffineTransformIdentity;
                     self.speedView.transform = CGAffineTransformIdentity;
                 } completion:nil];

まったく同じことを行います。

結果は、最初に間違った方向に変換の半分をジャンプするため、最終的な動きは希望の変換の半分になります。

なぜこれが起こっているのか本当に分かりませんか?

何か案は。

::編集::

可能性のあるあいまいさを解消する。

私はこれらの見解を彼らがいる場所に「跳ね返る」ようにしようとしているのではありません。私がアニメーション化しているビューは、画面の端にあるコントロールパネルのようなものです。ユーザーが「移動」を押すと、ビューがスライドして邪魔になります。ユーザーが「停止」ボタンを押すと、パネルがスライドしてビューに戻ります。

少なくとも彼らは昔はそうだった。自動レイアウトを有効にしたので(アプリの他の部分に必要です)、ビューのフレームを変更するだけでは済まないため、変換ルートに進みました。

この効果は、ビューをビューコントローラーに貼り付け、アニメーションを実行するボタンで確認できます。

ありがとう

29
Fogmeister

OK、WWDCビデオをもう一度見たとき、AutoLayoutを使用するときに最初に行う必要があることの1つは、setFrameの呼び出しを削除することだと述べています。

画面が複雑なため、自動レイアウトを完全に削除し、フレームの位置を使用して画面内でビューを移動しています。

ありがとう

8
Fogmeister

私はまったく同じ問題を抱えていたので、ここに私が思いついた解決策があります。

    CGAffineTransform transform = CGAffineTransformMake(1, 0, 0, 1, translation.x, translation.y);
    [UIView animateWithDuration:0.25 animations:^{
        _assetImageView.transform = transform;
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
    }];

したがって、[self.view layoutIfNeeded]を呼び出します。 animateブロックの内側。これがないと、あなたと同じ問題が発生し、最初に負の並進距離をジャンプしてから、そこから正しい位置にアニメートします。これをビューコントローラから呼び出しているので、selfはUIViewControllerのサブクラスです。あなたの場合、「self.view」は存在しないかもしれませんが、私はあなたがアイデアを得ることを望みます。

67
David Nesbitt

ここでの解決策はどれも私にとってうまくいきませんでした...私のアニメーションは常にスキップします。 (別のアニメーションの最後であった場合を除いて、ヒント)。

一部詳細:

これを行っていたビューには、一連のスケールがあり、すでにスタックに変換されています。

ソリューション:

キーフレームアニメーションを実行します。最初のキーが非常に短く、基本的に、最後のアニメーションで設定する必要のある変換を再適用します。

    UIView.animateKeyframesWithDuration(0.4, delay: 0.0, options: [.CalculationModeCubic], animations: { () -> Void in
        //reset start point
        UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.01, animations: { () -> Void in
            self.element.transform = initialTransform
        })

        UIView.addKeyframeWithRelativeStartTime(0.01, relativeDuration: 0.99, animations: { () -> Void in
            self.element.transform = finalTransform
        })
    }, completion: nil)
15
Andres Canella

私はこの問題についてApple Technical Supportに質問し、この応答を得たので、それはバグです。

iOS 8は現在、UIKitアニメーションの既知のバグを示しており、変換アニメーションは間違ったfromValueを取得します(主にアニメーションオブジェクトの位置に影響し、アニメーションの開始時に予期せず「ジャンプ」するように見えます)。

[...]

潜在的な修正が提供されるまでの回避策は、Core Animation APIにドロップダウンしてアニメーションをコーディングすることです。

7
denbec

アンドレアスの回答の改良版は次のとおりです。主な違いは、キーフレームを1つだけ指定して、コードを少なくできることです。

UIView.animateKeyframes(withDuration: animationDuration, delay: 0.0, options: [], animations: {
  UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0, animations: {
    animatedView.transform = newTransform
    })
  }, completion: nil)
2
bananabastard

このアニメーションが発生する前に、settingsViewまたはspeedViewに既に変換が適用されていますか?

これらのビューの変換が恒等変換(別名CGAffineTransformIdentity、別名変換なし)でない場合、それらの.frameプロパティにアクセスできません。

UIViewsのフレームプロパティは、変換が適用されている場合は無効です。代わりに「境界」を使用してください。

1
MikeS

2番目のアニメーションは、最初のアニメーションの現在の状態(終了したかどうかに関係なく)から発生させたいので、2番目のアニメーションを設定するときにUIViewAnimationOptionLayoutSubviewsオプションを使用することをお勧めします。

[UIView animateWithDuration:0.2
                      delay:0.0
                    options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionLayoutSubviews
                 animations:^{
                     self.settingsView.transform = CGAffineTransformIdentity;
                     self.speedView.transform = CGAffineTransformIdentity;
                 } completion:nil];

以下は、シンプルなビューコントローラーテンプレートを使用してテストするために使用したコードのサンプルです。

myviewcontroller.m:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.animatedView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 160, 80)];
    self.animatedView.backgroundColor = [UIColor yellowColor];

    [UIView animateWithDuration:0.2
                          delay:0.0
                        options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionLayoutSubviews
                     animations:^{
                         CGAffineTransform settingsTransform = CGAffineTransformMakeTranslation(self.animatedView.frame.size.width, 0);

                         self.animatedView.transform = settingsTransform;

                     }
                     completion:nil];
    self.buttonToTest = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    self.buttonToTest.frame = CGRectMake(90, 20, 80, 40);
    [self.buttonToTest setTitle:@"Click Me!" forState:UIControlStateNormal];
    [self.buttonToTest addTarget:self action:@selector(buttonClicked) forControlEvents:UIControlEventTouchUpInside];

    // set-up view hierarchy
    [self.view addSubview:self.buttonToTest];
    [self.view addSubview: self.animatedView];

}

- (void) buttonClicked
{
    [UIView animateWithDuration:.2
                          delay:0.0
                        options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionLayoutSubviews
                     animations:^{
                         self.animatedView.transform = CGAffineTransformIdentity;

                     }
                     completion:nil];
}
1
tiguero

私はこの問題を抱えており、次の方法で解決しました:

  1. 元のビューを非表示にする
  2. アニメーション化するビューをコピーする一時ビューを追加します
  3. 意図したとおりになるアニメーションを実行します
  4. 一時ビューを削除し、最終状態で元のビューを再表示します

お役に立てれば。

0
Gaz Long