I am creating an app that will show how a bubble sort works. The one problem I am having is the animation. It seems to be skipping and the animation is firing all at once. Within my if statement I want to swap the two images and animate the swap. Then I want a delay so once they swap it will go back through the loop and swap the next two images. Below is my code. I have tried many things like sleep() but it did not seems to work. The images are four boxes and I’m swapping them by left to right, smallest to largest.
for (int i = 0; i < 3; i++)
{
UIImageView *temp1 = [imagesArray objectAtIndex:i];
UIImageView *temp2 = [imagesArray objectAtIndex:i+1];
temp1Width = temp1.frame.size.width;
temp2Width = temp2.frame.size.width;
if (temp1Width > temp2Width)
{
CGPoint tempPoint = temp1.center;
[UIView animateWithDuration:1.0
delay: 1.0
options: nil
animations:^{
temp1.center = temp2.center;
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0
delay: 0.0
options: nil
animations:^{
temp2.center = tempPoint;
}
completion:^(BOOL finished){
}];
}];
[imagesArray exchangeObjectAtIndex:i+1 withObjectAtIndex:i];
}
}
Any Help would be appreciated.
If you apply an animation to a view that’s already being animated, the new animation replaces the existing animation. It doesn’t just get tacked on to the end. That’s why your version doesn’t work the way you want.
This happens even if you set a delay on the new animation. The existing animation will be removed, and the new animation will start after the specified delay. This prevents k20’s simple answer from working. (Too bad, because that would be a really easy solution.)
So, a very simple alternative is to defer adding each additional animation at all. This is pretty easy with the
dispatch_afterfunction. First, let’s factor out the code that swaps the views’ Y origins into a helper function:Now we can write the sort function, making it use
dispatch_afterto postpone each successive animation:So this is an ok solution, but it does have one shortcoming. It’s not easy to add a button that cancels the animations, because there’s no API that removes a pending
dispatch_afterblock from the queue.If you want to support cancelation, it’s better to explicitly manage the queue of pending operations. We can do that by adding an instance variable to hold the queue:
Then, we modify
sortButtonWasTappedto add a block to the queue instead of callingdispatch_after, and we make it start running the queue after it finishes sorting:We’re using the same
swapViewYOriginsfunction as before. We run the pending swaps like this:So, we just stop if the queue is empty. Otherwise, we take the first block off the queue, and we use it as the animation block of a
UIViewanimation. We give the animation a completion block that callsrunPendingSwapsagain, which starts the next pending animation (if there is one) after the current one finishes.To cancel, we can just set
pendingSwapsto nil:Note that if the user taps Cancel, the views will not necessarily be in the same order on the screen as they are in
imagesArray, becauseimagesArrayis fully sorted whensortButtonWasTappedreturns. We can fix that by sortingimagesArrayby Y origins (using the built-in sort) before starting the bubble sort:With this in place, you can click the Sort button, then click Cancel before the views have been fully sorted on screen, then click Sort again and it will resume (by performing bubble sort again).