Johnny Everson
Johnny Everson

Reputation: 8601

Animate UIButton state change

I'm using a UIButton with images for normal and highlighted states. They work as expected but I want to have some fading/merging transition and not just a sudden swap.

How can I do that?

Upvotes: 53

Views: 22696

Answers (7)

Nikolay Suvandzhiev
Nikolay Suvandzhiev

Reputation: 9075

If you're coming here after iOS 15 and use the new UIButton.Configuration, you might be using configurationUpdateHandler to determine and set the confiration. What you can do in such a case is to set the configuration (probably the last thing you do in your function), using the UIView.transition(with: button API, so something like this:

UIView.transition(with: button,
                  duration: 0.2,
                  options: [.transitionCrossDissolve,
                            .beginFromCurrentState,
                            .allowUserInteraction,
                            .curveEaseInOut],
                  animations: { button.configuration = configuration })

Upvotes: 1

seymatanoglu
seymatanoglu

Reputation: 151

using CustomButton instead of UIButton and overriding isHighlighted property worked for me;

class KeypadButton: UIButton {
    var highlightDuration: TimeInterval = 0.25
    
    override var isHighlighted: Bool {
        didSet {
            if oldValue == false && isHighlighted {
                highlight()
            } else if oldValue == true && !isHighlighted {
                unHighlight()
            }
        }
    }

    func highlight() {
        animateBackground(to: highlightedBackgroundColor, duration: highlightDuration)
    }

    func unHighlight() {
        animateBackground(to: normalBackgroundColor, duration: highlightDuration)
    }
    
    private func animateBackground(to color: UIColor?, duration: TimeInterval) {
        guard let color = color else { return }
        UIView.animate(withDuration: highlightDuration) {
            self.backgroundColor = color
        }
    }
}

Upvotes: 0

Federico Zanetello
Federico Zanetello

Reputation: 3451

@marián-Černý answer in Swift:

Swift 2

UIView.transitionWithView(button, 
    duration: 4.0, 
    options: .TransitionCrossDissolve, 
    animations: { button.highlighted = true },
    completion: nil)

Swift 3, 4, 5

UIView.transition(with: button, 
    duration: 4.0, 
    options: .transitionCrossDissolve, 
    animations: { button.isHighlighted = true },
    completion: nil)

Upvotes: 2

Marián Černý
Marián Černý

Reputation: 15778

This can be done using transition animation of a UIView. It does not matter the isHighlighted property is not animatable, because it transitions the whole view.

Swift 3

UIView.transition(with: button,
                  duration: 4.0,
                  options: .transitionCrossDissolve,
                  animations: { button.isHighlighted = true },
                  completion: nil)

Objective-C

[UIView transitionWithView:button
                  duration:4.0
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{ button.highlighted = YES; }
                completion:nil];

Upvotes: 126

Zorayr
Zorayr

Reputation: 24962

Here is a self contained solution that also supports a boolean animated flag.

- (void)setEnabled:(BOOL)enabled animated:(BOOL)animated
{
  if (_button.enabled == enabled) {
    return;
  }

  void (^transitionBlock)(void) = ^void(void) {
    _button.enabled = enabled;
  };

  if (animated) {
    [UIView transitionWithView:_button
                      duration:0.15
                       options:UIViewAnimationOptionTransitionCrossDissolve
                    animations:^{
                      transitionBlock();
                    }
                    completion:nil];
  } else {
    transitionBlock();
  }
}

Upvotes: 2

Arvin
Arvin

Reputation: 2616

UIButton inherits from UIView

So then you get its view and call beginAnimations:context:

Then all the appropriate setAnimation methods from there.

The following properties of the UIView class are animatable:

  • @property frame
  • @property bounds
  • @property center
  • @property transform
  • @property alpha
  • @property backgroundColor
  • @property contentStretch

Ref: UIView Class Reference

Upvotes: 2

Johnny Everson
Johnny Everson

Reputation: 8601

To accomplish that I extended UIButton. added a new property called hilightedImage with the following code:

- (void)setHilightImage:(UIImageView *)_hilightImage
{
    if (hilightImage != _hilightImage) {
        [hilightImage release];
        hilightImage = [_hilightImage retain];
    }
    [hilightImage setAlpha:0];
    [self addSubview:hilightImage];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.14];
    if(hilightImage){
        [hilightImage setAlpha:1];
    }
    [UIView commitAnimations];
    [super touchesBegan:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

    self.highlighted = FALSE;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.14];
    if(hilightImage){
        [hilightImage setAlpha:0];
    }

    [UIView commitAnimations];
    [super touchesEnded:touches withEvent:event];
}

Upvotes: 3

Related Questions