1

I have a simple animation that runs when a message is received. This works great if they are only receive one message. However if the user receives multiple messages within the animation, the animation starts over. I don't want this to happen though, I want the animation to finish before starting the next one. My thinking was to create some sort of queue that will loop through a dictionary with keys 'from' and 'body' but I am not sure if this is the best practice. Does anyone have any ideas?

- (void) messageReceived:(NSNotification *)notification
{

NSString *body = [[notification userInfo] valueForKey:@"body"];
NSString *from = [[notification userInfo] valueForKey:@"from"];
UILabel *usernameLabel = (UILabel *)[self.view viewWithTag:502];
usernameLabel.text = from;

 UILabel *messageLabel = (UILabel *)[self.view viewWithTag:503];
 messageLabel.text = body;
CGRect notificationFrame = notificationView.frame;
notificationFrame.origin.y = 0;

[UIView animateWithDuration:0.3
                          delay:0.0
                        options:UIViewAnimationOptionCurveEaseOut
                     animations:^{
                         notificationView.frame = notificationFrame;
                     }
                     completion:^(BOOL finished){

if (finished) {
                             [UIView animateWithDuration:0.3
                                                   delay:1.0
                                                 options:UIViewAnimationOptionCurveEaseOut
                                              animations:^{
                                                  CGRect oldNotificationFrame = notificationView.frame;
                                                  oldNotificationFrame.origin.y = -100;
                                                  notificationView.frame = oldNotificationFrame;
                                              }
                                              completion:NULL];
                         }


                     }];
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
Landon
  • 787
  • 1
  • 9
  • 19
  • what effect would you like to have happen when an animation is playing and a new animation is desired: queue it to play when current has finished? Do you want multiple animations to queue, or only the last to arrive (meaning only a single animation at most will ever be queued), or some other criteria (urgency)? Visualizing what you want to have happen will help you select the right container (NSArray, NSDictionary, &c.) and dispatch. Probably a class var `BOOL isAnimating = YES` check with an alternate animation will work. – Thompson Aug 13 '14 at 00:00
  • For example if the user receives 4 messages simultaneously, 4 animations will take place one after another so I guess to answer your question I want multiple animations to queue. – Landon Aug 13 '14 at 04:09

1 Answers1

3

I think you need a two-pronged approach; create and queue the messages, and then animate the message UNLESS one or more messages are already queued for animation; in that case, just queue the animation. When the animation finishes, the completion block will recurse until the queue is empty.

@implementation yourCLass {

    //  holds incoming animation requests in FIFO order
    NSMutableArray *animationQueue;

    //  control switch to avoid starting an animation if one is running
    BOOL isAnimating;
}

- (void) messageReceived:(NSNotification *)notification {

    //  pertinent message data is stored in a dict in the array
  NSString *body = [[notification userInfo] valueForKey:@"body"];
  NSString *from = [[notification userInfo] valueForKey:@"from"];

  NSDictionary *messageFacts = @{ @"body" : body,
                                  @"from" : from };

    //  most-recent messages get put into position zero; LIFO
    //  NB: this array has already been initialized elsewhere...
  [self->animationQueue insertObject:messageFacts
                             atIndex:0];

    //  now for animating BUT ONLY if not already animating (if already animating the queued
    //  animations will get animated anyway)
  if (!self->isAnimating) {

    [self animateMessages];
  }
}

- (void) animateMessages {

  if (self->animationQueue.count == 0) {
      //  all messages have been animated, clear isAnimating bit and exit

    self->isAnimating = NO;
    return;
  }

  self->isAnimating = YES;

  //  extract message data from array as a dictionary, delete from array
  NSDictionary *messageFacts = [self->animationQueue lastObject];
  [self->animationQueue removeLastObject];

  //  import message data from dictionary to labels
  UILabel *usernameLabel = (UILabel *)[self.view viewWithTag:502];
  usernameLabel.text = messageFacts[@"from"];

  UILabel *messageLabel = (UILabel *)[self.view viewWithTag:503];
  messageLabel.text = messageFacts[@"body"];

  //    other housekeeping
  CGRect notificationFrame = notificationView.frame;
  notificationFrame.origin.y = 0;

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

                     notificationView.frame = notificationFrame;
                   }
                   completion:^(BOOL finished){

                     if (finished) {

                       [UIView animateWithDuration:0.3
                                             delay:1.0
                                           options:UIViewAnimationOptionCurveEaseOut
                                        animations:^{

                                          CGRect oldNotificationFrame = notificationView.frame;
                                          oldNotificationFrame.origin.y = -100;
                                          notificationView.frame = oldNotificationFrame;
                                        }
                                        completion:^(BOOL finished){

                                          if (finished ) {

                                              //  when done, method recurs until all notifications have
                                              //  been animated
                                            [self animateMessages];
                                          }
                                        }];
                     }
                   }];
}
Thompson
  • 1,098
  • 11
  • 25