我有View
来显示和隐藏,以便为用户提供一些提示。
show and hide方法看起来像这样:
-(void)show{
[UIView animateWithDuration:3.0f
animations:^{
//do something to show self to give hint;
self.frame = CGRectMake(0,0,0,0);
} completion:nil];
}
-(void)hide{
[UIView animateWithDuration:3.0f
animations:^{
//do something to hide self to give hint;
self.frame = CGRectMake(centerX,centerY,100,100);
} completion:nil];
}
在展示新视图时,我必须致电hide method
,然后致电show method
。但持续时间延迟3.0f会导致一些错误。我正在使用这样的方法:
dispatch_async(dispatch_get_main_queue(), ^{
[view hide];
});
dispatch_async(dispatch_get_main_queue(), ^{
[view show];
});
我在show method
之后立即致电hide method
。动画无法按照提交到队列的顺序执行。我想要的是show method
完成hide method
后完成的show method
。如何控制这两种方法的顺序。
我认为我无法使用完成处理程序,因为我无法确定调用这两个方法的位置,或者当我调用另一个hide method
或show
时是否显示视图。
如果我不清楚,有什么建议吗?我会重复我的问题。
PS:
它不仅仅是闪光灯。当调用下一个hide
方法时,我无法确保显示最后一个视图或隐藏最后一个视图的显示时间,也就是说,如果正在显示视图并且show
方法具有调用并已完成,然后调用hide
方法,结果是正确的。如果正在显示视图,则需要显示另一个提示视图,我将首先调用show
,然后调用main_queue
,因为show
是串行的,但动画块是同步执行的,所以结果是错的。我在寻找GCD中是否有某种锁可以帮助我在最后一个排队块完成后执行一个块,而不是在hide
和show
方法中进行更改。因为有许多其他调用hide
和{{1}}方法的许多不同类型的参数,我需要在我的代码中修复很多地方。
答案 0 :(得分:1)
如果你想要的是一个动作(隐藏然后显示自己),你应该只做一个动画而不是加入两个动画。
有两种可能的解决方案。
(1)使用动画重复和自动反转(需要在完成回调时重置回原始大小)
-(void) flash {
CGRect bounds = self.bounds;
[UIView animateWithDuration:1.0f
delay:0.0f
options:UIViewAnimationOptionAutoreverse |
UIViewAnimationOptionRepeat
animations:^{
[UIView setAnimationRepeatCount:1];
self.bounds = CGRectZero;
}
completion:^(BOOL finished) {
self.bounds = bounds;
}];
}
(2)使用关键帧动画
-(void) flash2 {
[UIView animateKeyframesWithDuration:1.0f
delay:0.0f
options:UIViewKeyframeAnimationOptionCalculationModeLinear
animations:^{
CGRect bounds = self.bounds;
[UIView addKeyframeWithRelativeStartTime:0.0
relativeDuration:0.5
animations:^{ self.bounds = CGRectZero; }];
[UIView addKeyframeWithRelativeStartTime:0.5
relativeDuration:0.5
animations:^{ self.bounds = bounds; }];
}
completion:nil];
}
答案 1 :(得分:1)
如果要按照添加到队列的顺序一次执行一个任务,请使用串行队列。
因此,您可以使用串行队列以添加的顺序一次执行显示和隐藏任务。是的,主要队列是可以的。
然而UIView -animateWithDuration:animations:方法是一种异步调用,该方法立即返回。所以你需要等到调用完成块。
如果您想等到某些任务完成,请使用调度组。但你应该避免在主队列上这样等待。它阻止主队列。糟糕的应用。
因此,您可能需要使用串行队列和调度组作为以下内容。
属性并初始化
@property (nonatomic, strong) dispatch_queue_t serialQueue;
@property (nonatomic, strong) dispatch_group_t group;
-(void)initQueue {
// create a serial queue
self.serialQueue = dispatch_queue_create("com.example.serialQueue", 0);
// create a dispatch group
self.group = dispatch_group_create();
}
使用串行队列和调度组的方法
-(void)animateSyncWithDuration:(NSTimeInterval)duration animations:(block_t)animations {
dispatch_async(self.serialQueue, ^{
/*
* This block is invoked on the serial queue
* This block would never be executed concurrently
*/
/*
* Enter the dispatch group
*/
dispatch_group_enter(self.group);
dispatch_async(dispatch_get_main_queue(), ^{
/*
* This block is invoked on the main queue
* It is safe to use UIKit
*/
[UIView animateWithDuration:duration animations:animations completion:^{
/*
* This completion block is invoked on the main queue
* Now leave the dispatch group
*/
dispatch_group_leave(self.group);
}];
});
/*
* Wait until leaving the dispatch group from the UIView animation completion block
* It means it blocks the serial queue
*/
dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
});
}
显示和隐藏
-(void)show{
[self animateSyncWithDuration:3.0f animations:^{
//do something to show self to give hint;
self.frame = CGRectMake(0,0,0,0);
}];
}
-(void)hide{
[self animateSyncWithDuration:3.0f animations:^{
//do something to hide self to give hint;
self.frame = CGRectMake(centerX,centerY,100,100);
}];
}
答案 2 :(得分:0)
我使用以下方式将delay
放入function calling
。
- (void) doAnimation : (double) delay {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Call your First function here");
});
double delayInSeconds = delay;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
NSLog(@"Call your second function here");
});
}
答案 3 :(得分:0)
我可能没有完全理解用例,但我认为你应该在这里做的是检查是否真的需要进行隐藏操作。此外,由于隐藏在代码中的动画持续时间为3秒,因此您应该使用完成块创建方法,这样您就可以执行类似于我在伪代码中编写的内容:
- (void)hideIfNeededWithCompletionBlock:((^)())completionBlock {
if (self.isShowing) {
[self hideWithCompletionBlock:^(BOOL didHide) {
if (completionBlock) {
completionBlock();
}
}];
} else {
if (completionBlock) {
//We didn't need to hide anything, so we're done
completionBlock();
}
}
}
然后你可以这样称呼它:
[self hideIfNeededWithCompletionBlock:^(){
[self show];
}];
如果您需要灵活性,可以使用show方法执行类似的操作。
此外,根据您的需要,您可以使您的方法采用BOOL来设置是否为显示/隐藏设置动画,如果传递NO,则使用0.0的持续时间。
我认为它可以对抗UIView动画API,当你可以使用提供的API处理它时,开始将它包装在dispatch_async块中。