Preventing user input during UIView animations

て烟熏妆下的殇ゞ 提交于 2019-12-13 07:46:19

问题


I have a UIView animation (called by a touchesEnded: event) that I want to finish executing before more user input is allowed. Before the animation is called, I inspect a flag "isMoving" to see if the animation is in progress. I then set isMoving to YES and execute the animation as follows (yes, I know it's not in block format)...

- (void) methodCalledFromViewControllerTouchesEnded {
    if (isMoving == YES) {
        NSLog (@"Don't start another animation!");
        return;
    }   
    isMoving = YES;

    ......

    [UIView beginAnimations:@"move" context:NULL];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
    [UIView setAnimationDuration:0.25f];
    ...
    // DO MOVE STUFF
    ...
    [UIView commitAnimations];

    isMoving = NO;
}

I then set isMoving to NO so subsequent calls from touchesEnded: don't start another animation while the current one is in progress. However, this FAILS and the animations are done repeated times if the user keeps touching while the initial animation is in progress.

I wonder if this may have to with the possibility that the touch events are handled on a different thread than the animations.

I also ran in debug mode and noticed that the animations aren't actually "committed" until control has left methodCalledFromViewControllerTouchesEnded and returned to touchesEnded:, thus rendering the isMoving = NO; flag useless.

Any help in preventing the repeated animations would be much appreciated.


回答1:


If you use UIView's class method

+ (void)animateWithDuration:(NSTimeInterval)duration 
                 animations:(void (^)(void))animations

user interaction is disabled by default until the animation finishes. It would save you a lot of work. For you, you'd want to use the full method so you could use your EaseIn option. It would look like this

- (void) methodCalledFromViewControllerTouchesEnded {

        [UIView animateWithDuration:0.25f 
                              delay:0.0 
                            options:UIViewAnimationOptionCurveEaseIn 
                         animations:^(void){
                                     // You animations here
                         } 
                         completion: nil];

}

If you did it the way you currently are, you need to change a few things. Keep in mind that the animation is not blocking, so when you set isMoving to NO at the end, that happens IMMEDIATELY after the animation begins, not after it ends. Now, let me reiterate that the above code is much simpler than your method, but if you did want to continue down your path, you will want to set the animationStopped completion method for your animation, and in that method, set isMoving to NO. It would look like this:

isMoving = YES;
[UIView beginAnimations:@"move" context:NULL];
//...
[UIView setAnimationDidStopSelection:@selector(animationDidStop:finished:context:)];
// ... DO MOVE STUFF
//....
[UIView commitAnimations];

And then you would implement the selector like this:

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
     isMoving = NO;
}



回答2:


I had a similar problem, solved it with:

[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
[[UIApplication sharedApplication] endIgnoringInteractionEvents];



回答3:


You're stuff is correct, except you misunderstand how the animation works. It's working just as you told it to :P.

The problem is that you set isMoving to NO too soon. The animation block doesn't pause execution of the code. Instead it queues the animations and continues executing.

- (void) methodCalledFromViewControllerTouchesEnded {
    if (isMoving == YES) {
        NSLog (@"Don't start another animation!");
        return;
    }   
    isMoving = YES;

    [UIView animateWithDuration:.25 
                         animations:^(void){
                                     //DO STUFF HERE
                         } 
                         completion: ^(BOOL finished) {
                                     isMoving = NO;
                         }];
}

Is more of what you want.

If you really want to not do a block structure. Then go with something like

- (void) methodCalledFromViewControllerTouchesEnded {
    if (isMoving == YES) {
        NSLog (@"Don't start another animation!");
        return;
    }   
    isMoving = YES;

    ......

    [UIView beginAnimations:@"move" context:NULL];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
    [UIView setAnimationDuration:0.25f];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animate:finished:context:)];
    ...
    // DO MOVE STUFF
    ...
    [UIView commitAnimations];

}

-(void)animate:(NSString *)str_animationID finished:(BOOL)b_isFinished context:(void *)v_context {

    if(str_animationID == @"move") {
        isMoving = NO;
    } 
}


来源:https://stackoverflow.com/questions/5748337/preventing-user-input-during-uiview-animations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!