Reputation: 8601
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
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
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
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
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.
UIView.transition(with: button,
duration: 4.0,
options: .transitionCrossDissolve,
animations: { button.isHighlighted = true },
completion: nil)
[UIView transitionWithView:button
duration:4.0
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{ button.highlighted = YES; }
completion:nil];
Upvotes: 126
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
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:
Upvotes: 2
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