简体   繁体   中英

Sequential iOS animation *without* blocks?

How might one animate a UIView without using block structure? I just need to force an animation to execute immediately after it is called, and I don't have the luxury of putting the rest of my program in a completion block based on the code structure.

To be specific, right now, here is what is happening

while (actionsRemaining)
{
   [self performDesiredAnimation];
   ....computation ....
   [barWidget decreaseValueTo:resultOfComputation];
}

When I run this code, all [performDesiredAnimation] animations happen simultaneously with the 10 or so barWidgets all decreasing simultaneously. What I want is:

performDesiredAnimation1 --> barWidget decreases --> performedDesiredAnimation2 --> barWidget decreases --> performDesiredAnimation3 --> barWidget decreases --> ... however many unknown times.

I don't know how many times because actions will get removed from actionsRemaining if the barWidget decreases past a certain value, ie the number of loops will depend on intermediate calculations.

To put it even more simply, what I want is the same result as I am seeing now when I call just one iteration of the loop

[self performDesiredAnimation];
....computation ....
[barWidget decreaseValueTo:resultOfComputation];

, followed by the second iteration, followed by the third, all in isolation. Right now the animation looks fine if I comment out the loop, but they all smash together when I keep the loop there. I just want the animations to execute sequentially from iteration to iteration, not all at once.

Blocks are not what is causing you the problem. Your problem, I think, is your "animations in a for loop" structure.

You need to keep your animating actions in a stack, and when one is finished, pop the next one off the stack and perform that. Alternatively, check in the completion block for the animation if you need to continue, and if so, call the animating method again. Something like:

-(void)performAnimation
{
    [UIView animateWithDuration:0.25 
                     animations:^{[self performDesiredAnimations];}
                     completion:^(BOOL finished){
                                // It's not clear what your computations are or if they take any significant time
                                CGFloat result = [self doComputations];
                                [barWidget decreaseValueTo:resultOfComputation]
                                if (needToPerformAnotherSet) // Work this out however you need to
                                {
                                    [self performAnimation];
                                }
                            };
}

You can do this:

// Start the work in a background thread.

dispatch_async(dispatch_get_global_queue(0, 0), ^{

    while (actionsRemaining) {

        // Do your calculation in the background if your code will allow you to

        [self performDesiredAnimation];
        ....computation ....

        // Back to the main thread for a chunk of code

        dispatch_sync(dispatch_get_main_queue(), ^{

            // Or do it here if not

            [self performDesiredAnimation];
            ....computation ....

            // Finally, update your widget.

            [barWidget decreaseValueTo:resultOfComputation];
        }
    }
} 

}

Since your loop enters the async'ed background loop on each iteration the application's main run loop will get a chance to update your UI with the value that you set in the sync'd block.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM