在 UIButton down/up 上协调两个 UIView 动画

Posted

技术标签:

【中文标题】在 UIButton down/up 上协调两个 UIView 动画【英文标题】:Coordinating two UIView animations on UIButton down/up 【发布时间】:2014-06-19 03:20:08 【问题描述】:

我正在尝试围绕 UIButton 构建动画。 UIButton 有一个 UIImageView,其中包含一个图像,当 UIButton 被按住时我想缩小它,然后当 UIButton 松开时,我想播放一个单独的动画来执行反弹。

我现在遇到的问题是,如果我快速按下然后快速按下,动画的第二部分似乎没有播放。如果我按住(等待第一个动画完成),然后松开,它似乎工作正常。

以下是相关代码:

-(void)pressedDown

[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^
                self.heartPart.layer.transform = CATransform3DMakeScale(0.8, 0.8, 1);
             completion:nil];


-(void)pressedUp

[UIView animateWithDuration:0.8
                                      delay:0.0
                     usingSpringWithDamping:20
                      initialSpringVelocity:200
                                    options:UIViewAnimationOptionBeginFromCurrentState
                                 animations:^
                                     self.heartPart.layer.transform = CATransform3DIdentity;
                                 
                                 completion:nil];
            ];

在我的ViewDidLoad 中添加以下内容:

[self.heartButton addTarget:self
                     action:@selector(pressedUp)
           forControlEvents:UIControlEventTouchUpInside];

[self.heartButton addTarget:self
                     action:@selector(PressedDown)
           forControlEvents:UIControlEventTouchDown];

知道如何让两个动画按顺序排列并且即使在快速按下时也不会互相打断?

【问题讨论】:

您的意思是希望第一个动画在第二个动画开始之前完成,即使您快速触摸一下? 是的,现在似乎第二个动画根本没有触发,因为第一个动画还没有完成。 你真的需要第二个动画在用户抬起手指之前不开始吗?无论如何,人们似乎不会长时间保持触摸,在这种情况下,您只能有一个方法,并将第二个动画添加到第一个动画的完成块中...... 在按钮中抬起手指会在服务器上提交某些内容,因此我想播放更响亮的动画。如果您将手指从按钮上移开,那么我希望它取消(标准按钮行为)。这不是必需的,但这是我希望做的一个很好的接触。 :) 链接动画的方式有很多种。最明显的是有一个序列号NSOperationQueue。这样,您甚至可以取消尚未运行的动画,并在用户快速来回移动手指时安排新的动画。请记住,动画必须在主线程上调度,而 NSOperations 只会分拆并等待动画完成。 【参考方案1】:

这是一个潜在的行动计划。保留两个全局变量BOOL buttonPressedNSDate *buttonPressDate。按下按钮时,您应该将buttonPressed 设置为true,并将buttonPressDate 设置为当前日期。现在在 touch up 方法中,将 buttonPressed 设置为 false 并检查 buttonPressDate 与当前日期之间的时间间隔是否大于动画的持续时间。如果是,则运行修饰动画;如果没有,请返回。在 touch down 方法的完成块中,您将检查按钮是否仍被按下。如果是,则什么也不做;如果不再按下,则运行修饰动画。

使用这种方法你会得到的效果应该是这样的:如果你快速点击按钮,它将运行完整的 0.2 秒缩小动画,然后依次运行放大动画。

现在,如果您不希望在快速触摸的情况下运行触地动画,您可能应该延迟第一个动画并检查当您启动它时按钮是否仍被按下。如果是快速触摸,您将运行修改后的动画,涵盖触摸和触摸两个阶段。

【讨论】:

【参考方案2】:

您可以尝试以下方法:-

 //Set only one target with TouchUpInside.
  [self.heartButton addTarget:self
                 action:@selector(pressedUp)
       forControlEvents:UIControlEventTouchUpInside];


-(void)pressedDown

  [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^
            self.heartPart.layer.transform = CATransform3DMakeScale(0.8, 0.8, 1);
         
    completion:

    [self pressedUp];
    //Or
    [self performSelector:@selector(pressedUp) withObject:self afterDelay:0.5]; 

  ];       


 -(void)pressedUp
 
   [UIView animateWithDuration:0.8
                                  delay:0.0
                 usingSpringWithDamping:20
                  initialSpringVelocity:200
                                options:UIViewAnimationOptionBeginFromCurrentState
                             animations:^
                                 self.heartPart.layer.transform = CATransform3DIdentity;
                             
                             completion:nil];
        ];
 

这样,当第一个动画完成后,下一个动画就会开始。但我担心它看起来不合适,而且向用户展示的动画会有点长。这取决于您的应用设计以及它将通过它实现的所有目标。

【讨论】:

【参考方案3】:

我假设您熟悉操作的概念。如果没有,那么NSOperations 允许您保持代码模块化并允许您设置执行顺序。

您可以创建NSOperation 的自定义子类并在其执行块中运行动画,然后在每次用户与按钮交互时在队列中添加带有动画的操作。

除了documentation from Apple,Github 上有一个很好的例子来说明如何继承NSOperation

https://github.com/robertmryan/AFHTTPSessionOperation/blob/master/Source/AsynchronousOperation.m

基于您自定义操作的“蓝图”,实现您想要的非常简单,即:

@interface PressDownAnimationOperation : AsynchronousOperation

- (instancetype)initWithView:(UIView *)view;

@end

@implementation PressDownAnimationOperation 
    UIView *_view;


- (instancetype)initWithView:(UIView *)view 
    self = [super init];
    if(self) 
        _view = view;
    
    return self;


- (void)main 
    // dispatch UIKit related stuff on main thread
    dispatch_async(dispatch_get_main_queue(), ^
        // animate
        [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^
                _view.layer.transform = CATransform3DMakeScale(0.8, 0.8, 1);
             completion:^(BOOL finished)
              // mark operation as finished
              [self completeOperation];
            ];
    );


@end

现在为了运行动画,您需要创建NSOperationQueue。您可以将其保存在您的视图控制器中,即:

@implementation ViewController 
    NSOperationQueue *_animationQueue;


- (void)viewDidLoad 
    [super viewDidLoad];

    _animationQueue = [[NSOperationQueue alloc] init];

    // limit queue to run single operation at a time
    _animationQueue.maxOperationCount = 1;


@end

现在,当您想要链接动画时,您只需创建新操作,将其添加到队列中即可,即:

- (void)pressedDown 
    NSOperation *animationOperation = [[PressDownAnimationOperation alloc] init];

   [_animationQueue addOperation:animationOperation];

如果用户点击太快而您发现操作队列被动画阻塞,您可以在添加新动画之前简单地取消所有动画,即:

[_animationQueue cancelAllOperations];

【讨论】:

以上是关于在 UIButton down/up 上协调两个 UIView 动画的主要内容,如果未能解决你的问题,请参考以下文章

selenium 之 ActionChains (key_down,key_up,send_keys_to_element,send_keys)

使上/下箭头、Pos1、End、Del ... 更简单

eclipse/myeclipse中快捷键 Ctrl+shift+down/up 出现屏幕颠倒

leetcode376

selenium 使用键盘时 提示java.lang.IllegalArgumentException: Key Down / Up events only make sense for modifi

Eclipse常用快捷键总结