14

我想在两个 UIButton 图像之间淡入淡出,以便在 UITableView 中设置收藏夹。

目前过渡没有效果 - 它只是在点击/触摸时直接更改图像:

trans_img = [UIImage imageNamed:@"fav_on.png"];

NSArray *subviews = [owningCell subviews];
UIButton *favbutton = [subviews objectAtIndex:2];

favbutton.imageView.animationImages =
[NSArray arrayWithObjects:trans_img,
 nil];

[favbutton.imageView startAnimating];

我发现的一切都是 UIViews 之间的过渡 :(

如果图像 fav_off 能够顺利更改为 fav_on 并且反之,就像淡入/淡出一样,那就太好了。

4

8 回答 8

35

看起来你正在寻找的是这个。它为 UIButton 上的图像设置动画,而无需添加新图像、创建数组或更改 alpha 值!

CABasicAnimation *crossFade = [CABasicAnimation animationWithKeyPath:@"contents"];
crossFade.duration = 0.7;
crossFade.fromValue = (id)oldImage.CGImage;
crossFade.toValue = (id)newImage.CGImage;
crossFade.removedOnCompletion = NO;
crossFade.fillMode = kCAFillModeForwards;
[button.imageView.layer addAnimation:crossFade forKey:@"animateContents"];

//Make sure to add Image normally after so when the animation
//is done it is set to the new Image
[button setImage:newImage forState:UIControlStateNormal];
于 2014-03-20T04:08:24.587 回答
7

在这里迅速:

  import UIKit

   extension UIButton {

       func changeImageAnimated(image: UIImage?) {
           guard let imageView = self.imageView, currentImage = imageView.image, newImage = image else {
               return
           }
           let crossFade: CABasicAnimation = CABasicAnimation(keyPath: "contents")
           crossFade.duration = 0.3
           crossFade.fromValue = currentImage.CGImage
           crossFade.toValue = newImage.CGImage
           crossFade.removedOnCompletion = false
           crossFade.fillMode = kCAFillModeForwards
           imageView.layer.addAnimation(crossFade, forKey: "animateContents")
       }
   }


   self.playAndPauseVideo.changeImageAnimated(UIImage(named: "pauseVideo"))
于 2016-05-26T14:25:28.690 回答
6

感谢@jkanter 的出色回答。我把我的变成了一个 Swift 3.0 扩展,我认为它可能对任何偶然发现这篇文章的人都有用。

extension UIButton {

    func setImage(_ image: UIImage?, for state: UIControlState, animated: Bool) {
        guard animated, let oldImage = imageView?.image, let newImage = image else {
            // Revert to default functionality
            setImage(image, for: state)
            return
        }

        let crossFade = CABasicAnimation(keyPath:"contents")
        crossFade.duration = 0.35
        crossFade.fromValue = oldImage.cgImage
        crossFade.toValue = newImage.cgImage
        crossFade.isRemovedOnCompletion = false
        imageView?.layer.add(crossFade, forKey: "animateContents")

        setImage(image, for: state)
    }
}
于 2016-10-10T20:28:05.257 回答
3

您可以尝试像这样转换 alpha 值以获得您想要的效果:

trans_img = [UIImage imageNamed:@"fav_on.png"];

NSArray *subviews = [owningCell subviews];
UIButton *favbutton = [subviews objectAtIndex:2];
[UIView animateWithDuration:0.5 animations:^{
    favbutton.alpha = 0.0f;
} completion:^(BOOL finished) {
    favbutton.imageView.animationImages = [NSArray arrayWithObjects:trans_img,nil];
    [favbutton.imageView startAnimating];
    [UIView animateWithDuration:0.5 animations:^{
        favbutton.alpha = 1.0f;
    }];
}];
于 2013-05-29T01:49:49.520 回答
3

这是对@Ponja 的回答的轻微改进,通常效果很好。不幸的是,newImage 不会“粘住”,所以如果你想在两个图像之间切换,第一个淡入淡出会顺利进行,但回到原始图像会“快速”返回而不会淡入淡出。通过使用 CATransaction 修复它:

import UIKit

extension UIButton {
    func changeImageAnimated(image: UIImage?) {
        guard let imageView = self.imageView, currentImage = imageView.image, newImage = image else {
            return
        }
        CATransaction.begin()
        CATransaction.setCompletionBlock {
            self.setImage(newImage, forState: UIControlState.Normal)
        }
        let crossFade: CABasicAnimation = CABasicAnimation(keyPath: "contents")
        crossFade.duration = 0.3
        crossFade.fromValue = currentImage.CGImage
        crossFade.toValue = newImage.CGImage
        crossFade.removedOnCompletion = false
        crossFade.fillMode = kCAFillModeForwards
        imageView.layer.addAnimation(crossFade, forKey: "animateContents")
        CATransaction.commit()
    }
}
于 2016-06-30T18:13:34.333 回答
1

@SuperDuperTango 对 tintColor 的回答添加了:

extension UIButton {
    func changeImageAnimated(image: UIImage?) {
        guard let imageView = self.imageView, currentImage = imageView.image, newImage = image else {
            return
        }
        CATransaction.begin()
        CATransaction.setCompletionBlock {
            self.setImage(newImage, forState: UIControlState.Normal)
        }
        let crossFade: CABasicAnimation = CABasicAnimation(keyPath: "contents")
        crossFade.duration = 0.3
        crossFade.fromValue = currentImage.CGImage
        crossFade.toValue = newImage.CGImage
        crossFade.removedOnCompletion = false
        crossFade.fillMode = kCAFillModeForwards
        imageView.layer.addAnimation(crossFade, forKey: "animateContents")
        CATransaction.commit()

        let crossFadeColor: CABasicAnimation = CABasicAnimation(keyPath: "contents")
        crossFadeColor.duration = 0.3
        crossFadeColor.fromValue = UIColor.blackColor()
        crossFadeColor.toValue = UIColor(red: 232.0/255.0, green: 85.0/255.0, blue: 71.0/255.0, alpha: 1.0)
        crossFadeColor.removedOnCompletion = false
        crossFadeColor.fillMode = kCAFillModeForwards
        imageView.layer.addAnimation(crossFadeColor, forKey: "animateContents")
        CATransaction.commit()
    }
}
于 2016-07-15T13:03:38.290 回答
0

@SuperDuperTango 在 Swift 4.2 中的回答:

extension UIButton {
    func changeImageAnimated(image: UIImage?) {
        guard let imageView = self.imageView, let currentImage = imageView.image, let newImage = image else { return }

        CATransaction.begin()
        CATransaction.setCompletionBlock {
            self.setImage(newImage, for: .normal)
        }
        let crossFade: CABasicAnimation = CABasicAnimation(keyPath: "contents")
        crossFade.duration = 0.3
        crossFade.fromValue = currentImage.cgImage
        crossFade.toValue = newImage.cgImage
        crossFade.isRemovedOnCompletion = false
        crossFade.fillMode = CAMediaTimingFillMode.forwards
        imageView.layer.add(crossFade, forKey: "animateContents")
        CATransaction.commit()
    }
}
于 2019-04-10T08:40:46.100 回答
-1

jkanter用Swift回答:

let crossFade = CABasicAnimation.init(keyPath: "contents")
crossFade.duration = 0.7
crossFade.fromValue = oldImage.cgImage
crossFade.toValue = newImage.cgImage
crossFade.isRemovedOnCompletion = false
crossFade.fillMode = kCAFillModeForwards
button.imageView?.layer.add(crossFade, forKey: "animateContents")

//Make sure to add Image normally after so when the animation
//is done it is set to the new Image
button.setImage(newImage, for: .normal)
于 2017-07-26T06:01:15.287 回答