2013-03-01 41 views
3

用户可以用滑动手势启动动画。我想阻止对动画的重复调用,以确保动画一旦启动,它就不能再次启动,直到它完成 - 这可能发生在用户意外滑动多次的情况下。如何在Objective-C中可靠地阻止重复的动画调用?

我想大多数人使用布尔标志(BOOL isAnimatingFlag)以底部显示的方式实现此控制。我之前在应用中做过很多次这样的事情 - 但我从未完全肯定我的国旗是否有我想要的价值,因为动画使用了块,而且我不清楚我的动画完成了什么线程块正在运行。

这样(阻止重复动画)对于多线程执行可靠吗?

/* 'atomic' doesn't 
* guarantee thread safety 
* I've set up my flag as follows: 
* Does this look correct for the intended usage? 
*/ 
@property (assign, nonatomic) BOOL IsAnimatingFlag; 

//… 

@synthesize IsAnimatingFlag 

//… 

-(void)startTheAnimation{ 

// (1) return if IsAnimatingFlag is true 
if(self.IsAnimatingFlag == YES)return; 

/* (2) set IsAnimatingFlag to true 
* my intention is to prevent duplicate animations 
* which may be caused by an unwanted double-tap 
*/ 
self.etiIsAnimating = YES; 


    // (3) start a new animation 
    [UIView animateWithDuration:0.75 delay:0.0 options:nil animations:^{ 

    // animations would happen here... 

    } completion:^(BOOL finished) { 

    // (4) reset the flag to enable further animations 
     self.IsAnimatingFlag = NO; 
    }]; 
} 
+1

当用户按下按钮时,您可以禁用该按钮,直到动画结束,然后您可以再次启用该按钮。这应该可以解决你的问题。 – darren102 2013-03-01 14:33:21

+0

如何在开始动画并在完成块中再次启用之前禁用按钮? – trojanfoe 2013-03-01 14:34:32

+0

对不起朋友,动画实际上是由一个手势开始的,所以我应该删除“按钮”引用。我试图让事情变得简单,但却带来了混乱。编辑并更新。 – sean 2013-03-01 14:37:19

回答

4

禁用手势,如果你不希望用户多次

- (void)startTheAnimation:(id)sender 
{ 
    [sender setEnabled:NO]; 

    [UIView animateWithDuration:0.75 delay:0.0 options:nil animations:^{ 

    // animations would happen here... 

    } completion:^(BOOL finished) { 
    [sender setEnabled:YES]; 
    }]; 
} 

触发它更新

手势也有一个enabled属性,所以你可以使用相同的想法,如果它是一个按钮,并将其更改为启用状态

+0

谢谢@ Paul.s。但我想我正在寻找一个更通用的解决方案来阻止重复的动画,而不管启动动画是什么。例如:在某些视图中通过触摸启动动画时,我们应该做些什么? – sean 2013-03-01 14:46:21

+1

将“UITestRecognizer”的子类作为“UITapGestureRecognizer”来检测触摸。这种模式看起来比添加'BOOL'更好。如果你正在处理一个实际的视图,你可以用'userInteractionEnabled'做一些类似的事情。 – 2013-03-01 14:49:34

+0

似乎我应该真正挂钩这些属性(例如isEnabled/userInteractionEnabled),而不是设置这些BOOL,穿过我的手指,并希望最好的笑声。谢谢你。 – sean 2013-03-01 14:58:07

0

当你调用这个方法,你可以尝试使用dispatch_once GCD功能:

static dispatch_once_t onceToken; 
dispatch_once(&onceToken, ^{ 
    [myThingy startTheAnimation]; 
}); 
+2

它将如何重置,以便用户可以再次动画? – trojanfoe 2013-03-01 14:37:17

+0

好点。根据Paul.s的答案禁用该按钮是更好的解决方案。 – 2013-03-01 14:41:09

2

动画完成块将始终在主线程上运行。

UIView Class Reference的示例中,您可以看到[view removeFromSuperview]是直接从该块中调用的。这意味着一个完成块在主线程上运行,因为它是唯一可以调用UI相关方法的线程。

因此,如果您只从主线程中调用startTheAnimation,那么你们都很好。如果你不需要在主线程上调用它,因为你调用UI相关的方法。

如果您需要调用startTheAnimation其他线程比主线程你可以做这样的事情:

-(void)startTheAnimation{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     // Your code here 
    }); 
} 

当然,这是从以用户体验好点,例如,禁用一个按钮或以其他方式修改UI以指示动画正在进行中。但是,它们都是相同的代码。无论您需要做什么,首先需要在动画开始之前将其禁用,并在完成后重新启用它。

+0

+1非常有用的参考苹果文档[查看removeFromSuperview] - 正如你所提到的,确实表示完成块运行在主线程上。感谢您的确认 – sean 2013-03-01 15:01:39