John Drake
John Drake

Reputation: 183

Design Pattern for Sequential Core Animations

I'm working on a OS X application where I have a NSView that keeps track of connection state. If the connection is up, a green dot is displayed, if the connection is down, a red dot is displayed.

I wanted to animate this using Core Animation, however, I'm having trouble in situations where the connection state changes rapidly. Because the animation occurs in another thread, and doesn't block, when I get the current location of the view, if its still animating, I get something in-between what I want.

For example, within my NSView I have a @property called connectionState that I am overriding to set the state and animate the green and red dots.

- (void)setConnectionState:(BOOL)online
{
   NSPoint newPosition;
   if (online) { 
      newPosition = NSMakePoint(self.iconView.frame.origin.x, 
                                self.iconView.frame.origin.y + 32);
   } else { 
      newPosition = NSMakePoint(self.iconView.frame.origin.x, 
                                self.iconView.frame.origin.y - 32);
   }

   [NSAnimationContext beginGrouping];
   [[NSAnimationContext currentContext] setDuration:0.5];
   [self.iconView.animator setFrameOrigin:newPosition];
   [NSAnimationContext endGrouping];

   _connectionState = online;
}

As I'm sure you can see, if the connection state changes rapidly, self.iconView.frame is not correct and newPosition ends up being misaligned.

What I'd like to see is the view animate itself, wait until its complete, then animate itself again.

I've thought perhaps the solution should be to create a queue, then keep adding the connection state information into the queue in one thread, then have another thread in the background that has a while(true) statement within which it pulls from that queue, animates, waits for completion, and does this ad infinitum. However, this seems like a very clunky solution.

What's the correct design pattern to solve the problem?

Upvotes: 0

Views: 404

Answers (2)

nielsbot
nielsbot

Reputation: 16031

Seems like the correct solution is to know the actual values you want to animate to instead of using values based on the current state of your view (which could be anything)

- (void)setConnectionState:(BOOL)online
{
   const NSPoint kViewOnPosition = {...} ;
   const NSPoint kViewOffPosition = {...} ;

   NSPoint newPosition = online ? kOnPosition : kOffPosition ;

   [NSAnimationContext beginGrouping];
   [[NSAnimationContext currentContext] setDuration:0.5];
   [self.iconView.animator setFrameOrigin:newPosition];
   [NSAnimationContext endGrouping];

   _connectionState = online;
}

Upvotes: 1

Kevin Grant
Kevin Grant

Reputation: 5431

Unfortunately only available in Mac OS X 10.7, there is a setCompletionHandler: method on NSAnimationContext that you could use to detect when the animation is done (so, set a flag somewhere when you start, and unset that flag in the handler to mark the completion of animation). That way you can tell if there is already some animation in progress at the time another animation is supposed to start.

(I hope there is a better way but this is what occurs to me.)

Upvotes: 0

Related Questions