10

UIViewリモート通知が来たときに、5秒間画面にカスタムディスプレイを作成しようとしています。

次のようなコード:

//customView.alpha = 1.0 here
[UIView animateWithDuration:1 animations:^{
                                  customView.alpha = 0.3;
                              } 
                              completion:^(BOOL finished){
                                  // remove customView from super view.
                              }];

問題と必要なもの

ただし、いくつかの通知が短い時間間隔で来る場合があり、複数customViewが同時にアニメーション化され、1 つが他のものをカバーする場合があります。

これらのアニメーションが競合しないように、次々と実行してほしい。

仮定したが失敗

//(dispatch_queue_t)queue was created in other parts of the code
dispatch_sync(queue, ^{
    [UIView animationWithDuration:animations:...];
});

GCD キューでアニメーションを作成した後、GCD を使用しない元のコードと同じ結果が得られました。アニメーションはまだ競合しています。

ところで、 UI を含むアニメーションまたはタスクは常にメイン スレッドで実行する必要があると聞きましたが、2 番目のコードではアニメーションがスムーズに実行されたように見えました。なんで?

4

5 に答える 5

4

キューを使用してアニメーションを順番に送信することはできません。これは、アニメーションを開始するメソッドがすぐに戻り、アニメーションがアニメーション ツリーに追加されて後で実行されるためです。キュー内の各エントリは、ほんの一瞬で完了します。

各アニメーションが同じビューで動作する場合、システムはデフォルトで、次のアニメーションを開始する前に各アニメーションの実行を終了させる必要があります。

UIViewAnimationOptionBeginFromCurrentState オプション値のドキュメントを引用するには:

UIViewAnimationOptionBeginFromCurrentState

すでに実行中のアニメーションに関連付けられている現在の設定からアニメーションを開始します。 このキーが存在しない場合、進行中のアニメーションは、新しいアニメーションが開始される前に終了できます。別のアニメーションが進行中でない場合、このキーは効果がありません。

一連のアニメーションを連鎖させたい場合は、次のようにします。

アニメーション ブロックの変更可能な配列を作成します。(コード ブロックはオブジェクトであり、配列に追加できます。) 一番上のアニメーション ブロックを配列から取り出して (そして配列から削除し)、animateWithDuration:animations:completion を使用して送信するメソッドを作成します。ここで、完了メソッドは単純です。メソッドを再度呼び出します。コードが配列から項目を取り出す前にロックをアサートし、項目を削除した後にロックを解放するようにします。

次に、アニメーション配列ロックをアサートし、ロックにアニメーション ブロックを追加し、ロックを解放することで、着信通知に応答するコードを記述できます。

于 2012-05-30T20:58:54.077 に答える
4

毎回実行されるのが同じアニメーションである場合は、アニメーションを実行する回数を格納するだけで済みます (アニメーションの繰り返し回数プロパティとは異なります)。

リモート通知を受信したら、カウンターをインクリメントし、カウンターがちょうど 1 の場合にアニメーション化するメソッドを呼び出します。次に、methodThatAnimates で、毎回カウンターを減らしながら、完了ブロックで自分自身を再帰的に呼び出します。次のようになります (疑似コード メソッド名を使用)。

- (void)methodThatIsRunWhenTheNotificationIsReceived {
    // Do other stuff here I assume...
    self.numberOfTimesToRunAnimation = self.numberOfTimesToRunAnimation + 1;
    if ([self.numberOfTimesToRunAnimation == 1]) {
        [self methodThatAnimates];
    }
}

- (void)methodThatAnimates {
    if (self.numberOfTimesToRunAnimation > 0) {
        // Animation preparations ...
        [UIView animateWithDuration:1 
                         animations:^{
                                  customView.alpha = 0.3;
                         } 
                         completion:^(BOOL finished){
                                  // Animation clean up ...
                                  self.numberOfTimesToRunAnimation = self.numberOfTimesToRunAnimation - 1;
                                  [self methodThatAnimates];
                         }];
    }
}
于 2012-05-30T14:48:54.297 に答える
1

(非)同時NSOperationQueueを使用して、アニメーションを「段階的に」実行できます

NSOperationQueue クラスは、一連の NSOperation オブジェクトの実行を規制します。キューに追加された操作は、明示的に取り消されるか、そのタスクの実行が終了するまで、そのキューに残ります。キュー内の (まだ実行されていない) 操作は、優先度レベルと操作オブジェクト間の依存関係に従って編成され、それに応じて実行されます。アプリケーションは、複数の操作キューを作成し、それらのいずれかに操作を送信できます。

操作間の依存関係により、操作が異なる操作キューにある場合でも、操作の絶対的な実行順序が提供されます。操作オブジェクトは、依存するすべての操作の実行が完了するまで、実行の準備ができているとは見なされません。実行の準備ができている操作の場合、操作キューは常に、他の準備ができている操作と比較して最も優先度の高い操作を実行します。

于 2012-05-30T13:56:34.753 に答える
0

アニメーションをトリガーしているオブジェクトに、完了ブロックでメッセージを送信することをお勧めします。次に、そのオブジェクトが通知自体をキューに入れ、メッセージを受信するたびに次の通知を開始することができます。

于 2012-05-30T13:55:06.777 に答える