【问题标题】:Stopping all animations being performed on different thread停止在不同线程上执行的所有动画
【发布时间】:2011-11-06 13:53:20
【问题描述】:

我有一个菜单,其中的项目每隔 3 秒就会一个接一个地弹出,我这样做是这样的:

for(UIButton *menuItem in menuItems){
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0.3 * i) * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
        [menuItem setAlpha:1.0];
    }                             
}

是否可以在中间停止动画(例如,当触摸按钮时)? 我尝试将所有内容都设置为 alpha 1.0,但正如预期的那样,线程继续运行并再次显示项目。

将不胜感激任何想法:)
谢。

【问题讨论】:

  • 与您的问题无关,但现在 UIKit 线程安全吗?
  • 我真的不知道那是什么意思:>
  • 除非在 iOS5 上发生了变化(我认为他们没有),否则你只应该通过主线程更新你的 UI。您的调度队列正在后台线程上更新 UI,这可能会导致您的应用出现不稳定问题。这是官方文档中的一些内容(页面底部)developer.apple.com/library/ios/#documentation/uikit/reference/…
  • 我明白了。我实际上找不到更好的方法来做我想做的事。 (我想以 0.3 秒的间隔显示我的菜单项)。您会使用其他任何技术吗?非常感谢您指出这一点:)
  • 您的问题仍然有效并且是一个很好的问题。如果我能提供帮助,我会考虑一下并在这里发布一些内容。

标签: ios nsthread uiviewanimation


【解决方案1】:

您可以使用基于 UIView 块的动画制作动画,并设置 delay:。那里没有线程担心。

可以通过使用选项UIViewAnimationOptionBeginFromCurrentStateset 启动另一个基于块的动画来中断这些动画。

对于 alpha 过渡,这很好,因为动画的当前位置无关紧要。如果您正在移动对象,您可以通过查询保存对象当前状态的view.layer.presentationLayer 来获取当前位置。您将需要导入 QuartzCore 框架来执行此操作。这也为您提供了一个方法,removeAllAnimations,它几乎可以像听起来那样做,并将任何视图直接带到它已挂起或活动的任何动画的端点。

【讨论】:

  • 问题我不只是在播放 alpha,我还在用 CocoDenshion 播放声音。我会试试你的方法,看看它是否有效。谢谢人:)
  • 以下代码同时显示所有项目而不是延迟,由于某种原因:pastebin.com/dVEzCEWr
  • 直到动画结束才执行完成块。在设置每个动画之前,在 for 循环中增加 i 。我正要补充一点,您可以在完成块中播放声音,如果动画被中断,BOOL 参数将为 NO,因此您知道不播放声音。
  • 我真的不明白为什么在完成块中增加 i 是错误的,因为 - 我只需要在动画结束时将其增加 1,不是吗?无论如何,您的解决方案很完美,谢谢您的帮助:)
  • 它只能让我在 10 小时内给予赏金所以...... :) 提前抱歉
【解决方案2】:

我认为您无法停止已安排好的动画。但是您可以使用BOOL 标志设置一个实例变量,指示按钮是否已被按下。

例如,假设您的按钮的目标是方法buttonTapped

将您的标志初始化为NO

- (id)init {
    if (self = [super init]) {
        buttonAlreadyTapped = NO;
    }

    return self;
}

在按钮的目标中,将标志设置为YES

- (void)buttonTapped {
    self.buttonAlreadyTapped = YES;
}

并且仅在标志为NO 时修改alpha

for (NSInteger i = 1; i <= [menuItems count]; i++) {        
    UIButton *menuItem = [menuItems objectAtIndex:i-1];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (3 * i) * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
        if (!self.buttonAlreadyTapped) {
            menuItem.alpha = 1.0f;
        }
    });
}

请记住,向UIKit 发送消息应该始终在主线程上完成。

for (NSInteger i = 1; i <= [menuItems count]; i++) {        
    UIButton *menuItem = [menuItems objectAtIndex:i-1];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (3 * i) * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
        if (!self.buttonAlreadyTapped) {
            dispatch_async(dispatch_get_main_queue(), ^{
                menuItem.alpha = 1.0f;
            });
        }
    });
}

【讨论】:

  • 我已经在这样做了,但这并没有真正的帮助。我正在一个一个地显示 6 个菜单项,当用户单击其中一个时,我想停止进入动画并显示所有菜单项,并取消队列中的动画
  • +1 用于主线程提示,不知道 (dispatch_async in dispatch_after) 。谢谢人:)
【解决方案3】:

也许你会在this回复中找到答案,也许你会以其他方式做你的事情。

【讨论】:

  • 这条评论主要告诉我 dispatch_async 方法不是正确的方法,除非我们谈论 [NSThread performSelector],否则它并没有真正提供替代方案,即使那样,我也不会有回答我上面的问题(已安排停止动画)。
  • 另外,尽管我很感激您的时间 - 我不认为一句话和一个链接被视为答案。下次应该有评论。再次感谢您的宝贵时间。
  • 没问题。我找到了延迟和取消块的 NSObject 类别的这个要点源代码gist.github.com/955123 如果您将使用这些方法创建块实例并尝试保存它们,那么您可以调用 cancelBlock: 方法来取消它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多