13

I'm trying to animate a UIButton. But during it's animation, there is no interaction with the UIButton. Expected behavior is to be able to click on the button while it's moving. Here's the code snippet of the UIButton and animation:

UIImage *cloudImage = [UIImage imageNamed:@"sprite.png"];    
UIButton moveBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[moveBtn setFrame:CGRectMake(0.0, 80.0, cloudImage.size.width, cloudImage.size.height)];
[moveBtn setImage:cloudImage forState:UIControlStateNormal];
[moveBtn addTarget:self action:@selector(hit:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:moveBtn];
CGPoint newLeftCenter = CGPointMake( 300.0f + moveBtn.frame.size.width / 2.0f, moveBtn.center.y);
[UIView beginAnimations:nil context:nil]; 
[UIView setAnimationDuration:5.0f];
[UIView setAnimationRepeatCount:HUGE_VALF];
moveBtn.center = newLeftCenter;
[UIView commitAnimations];

hit selector just displays an NSLog to show if the button respond to it or not. Any help would be appreciated.

Matteo Alessani
  • 9,864
  • 4
  • 37
  • 56
Frank
  • 2,913
  • 5
  • 36
  • 66

5 Answers5

29

Try setting the animation option to UIViewAnimationOptionAllowUserInteraction.

[UIView animateWithDuration:.2
                      delay: 0
                    options: UIViewAnimationOptionAllowUserInteraction
                 animations:^{ 
                     // animation logic
                 }
                 completion:^(BOOL completed) { 
                     // completion logic
                 }
 ];
csano
  • 12,342
  • 2
  • 25
  • 44
  • 1
    Worked great. I had a UIButton that pulsed by animating the backgroundColor. Adding this option solved my problem. Thanks. – TMilligan May 16 '13 at 20:29
  • +1 This worked for me. Thanks! If you are using "animateWithDuration" for your UIButton animation, this is likely the solution. – mr.sosa Jun 03 '14 at 00:32
  • to combine many options: --objC: UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveEaseIn -- swift: options: [UIViewAnimationOptions.CurveEaseIn, UIViewAnimationOptions.AllowUserInteraction] – drpawelo May 19 '16 at 10:26
13

There were some questions here recently about this. The animation is purely visual. You can tap the button in it'd old frame until the animation is complete, when it finishes, the actual button jumps.

EDIT:

This answer is what I was referring to. You need to manually move the button with an NSTimer, apparently. See the linked question/answer for more.

Other folks suggest passing UIViewAnimationOptionAllowUserInteraction as a UIViewAnimation option.

Community
  • 1
  • 1
Moshe
  • 55,729
  • 73
  • 263
  • 420
  • basically my animation is going from left to right, I can't wait till the animation complete. this will defeat the purpose of having a button there in the first place, since it's just to have the ability to touch it during it's movement. – Frank Jun 14 '11 at 15:59
  • ah cool thx, i added a touchBegan and detected the rect that's being touched, this is working for me, although it would have been cool if the button would be clickable during the animation slide :( – Frank Jun 14 '11 at 19:26
2

For swift 4 this code works,

UIView.animate(withDuration: 2, delay: 0, options: [.autoreverse, .repeat, .allowUserInteraction],
                   animations: {
                    self.btnCashGame?.frame.origin.y -= 15



    },completion:  { (finished: Bool) in
        self.btnCashGame?.frame.origin.y += 15

    })
0

Another option is to add a transparent button over the button you are animating. In your particular case you might not be able to use this, as you are moving the button, but you might be able to create an overlay button big enough to cover from the start position to the final one.

I had this problem, and in my case using UIViewAnimationOptionAllowUserInteraction didn't work. I was animating the alpha of a UIButton inside a UIBarButtonItem (created with initWithCustomView:) to make a pulsating effect, and that option wouldn't work. I don't like the NSTimer option either (not smooth), so in the end I just added an overlay button, which I don't like, but works flawlessly.

José Manuel Sánchez
  • 5,111
  • 2
  • 29
  • 24
0

This problem is caused by large animations per block. I made an NSTimer based solution, like the one suggested above, and it worked... yet the movement was jerky (unless I inserted animation within every timer event trigger).

So, since animation was required anyway, I found a solution which requires no timer. It animates only a short distance and thus the button click is still accurate, with only a small error which is my case is very unnoticeable in the UI, and can be reduced depending on your params.

Note below that the error at any given time is < 15.0, which can be reduced for more accuracy depending on your animation speed requirements. You can also reduce the duration time for more speed.

- (void)conveyComplete:(UIView*)v
{
    [self convey:v delay:0];
}

- (void)convey:(UIView*)v delay:(int)nDelay
{
    [UIView animateWithDuration:.5 
                          delay:nDelay
                        options:(UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction)  
                     animations: ^
                    {
                        CGRect rPos = v.frame; 
                        rPos.origin.x -= 15.0;
                        v.frame = rPos;
                    }
                    completion: ^(BOOL finished)
                    {
                        [self conveyComplete:v];
                    }];

}
paiego
  • 3,270
  • 28
  • 37