2011-04-21 75 views
0

我有一个UIView动画(由touchesEnded:事件调用),我想在允许更多用户输入之前完成执行。在动画被调用之前,我检查一个标志“isMoving”以查看动画是否正在进行。然后我设置isMovingYES并执行如下动画(是的,我知道这是不是块格式)...在UIView动画期间防止用户输入

- (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; 
} 

然后我设置isMovingNO所以后续调用从touchesEnded:不启动另一个动画而目前正在进行中。但是,如果用户在初始动画进行过程中保持触摸,则会重复执行此FAILS和动画。

我不知道这是否有可能触摸事件是在不同的线程上处理的,而不是动画。

我也跑在调试模式下,发现该动画实际上不是“提交”,直到控制已经离开methodCalledFromViewControllerTouchesEnded,回到touchesEnded:,从而使该isMoving = NO;标志形同虚设。

任何帮助防止重复的动画将不胜感激。

回答

6

如果您使用的UIView的类方法

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

用户交互默认情况下禁用,直到动画完成。这会为你节省很多工作。对于你来说,你会想要使用完整的方法,以便使用你的EaseIn选项。它看起来像这样

- (void) methodCalledFromViewControllerTouchesEnded { 

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

} 

如果按照你现在的样子,你需要改变一些东西。请记住,动画没有被阻挡,因此当您在最后将isMoving设置为NO时,动画会在动画开始后立即发生,而不是在结束后发生。现在让我重申一下,上面的代码比你的方法简单得多,但是如果你想继续下去,你需要为动画设置animationStopped完成方法,并且在该方法中,将isMoving设置为NO。它应该是这样的:

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

然后你会实现这样的选择:

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

完美!我一直在嘲笑我的头数超过我想要承认的时间!我一直在避免转换到这里显示的块格式,因为我有几个将不得不效仿。但现在我想这将是值得的!我欠你一杯啤酒。 – 2011-04-21 18:50:04

+0

我编辑了我的答案,以非块方式向您展示。 – Christian 2011-04-21 18:54:18

1

你的东西是正确的,除非你误解如何动画作品。它正如你所说的那样工作:P。

问题是,您设置isMoving为过早。动画块不会暂停执行代码。相反,它排队动画并继续执行。

- (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; 
         }]; 
} 

更多的是你想要的。

如果你真的不想做块结构。然后用东西去像

- (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; 
    } 
} 
+0

只需要注意上面的代码,默认情况下UIView的块动画会阻止用户交互,所以上面的代码是矫枉过正的。要在动画期间启用用户交互,您需要完整的块动画方法,并将UIViewAnimationOptionAllowUserInteraction作为其中一个选项传递。 – Christian 2011-04-21 18:56:13

+0

+1非常好。谢谢。然而,我刚刚将答案交给了基督徒,正如他首先提出的。 – 2011-04-21 18:57:29

+0

是的,没关系。只是想给你你失踪的信息:P。我记得当我第一次开始UIView动画时(WAYYYYY在块被实现之前)我想哭。至于它是“过度杀伤”,对于这个具体的实施来说也是如此。您可能希望用更重要的动画重载动画。我在我的应用程序中经常这样做。所以即使发生动画也能够指定动画。 – ColdLogic 2011-04-21 19:31:21

4

我有一个类似的问题,以解决它:

[[UIApplication sharedApplication] beginIgnoringInteractionEvents]; 
[[UIApplication sharedApplication] endIgnoringInteractionEvents]; 
+0

这是我认为的最佳答案。 – 2014-04-11 11:33:19