【问题标题】:fade between two UIButton images在两个 UIButton 图像之间淡入淡出
【发布时间】:2013-05-24 00:12:23
【问题描述】:

我想在两个 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];

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

如果图像 fav_off 能够平滑地更改为 fav_on 并且反过来像淡入/淡出一样,那就太好了。

【问题讨论】:

    标签: ios uibutton fadein transition


    【解决方案1】:

    @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()
        }
    }
    

    【讨论】:

      【解决方案2】:

      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)
      

      【讨论】:

      • 为什么投反对票?我很好,但请不要犹豫,说出原因。
      【解决方案3】:

      感谢@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)
          }
      }
      

      【讨论】:

        【解决方案4】:

        @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()
            }
        }
        

        【讨论】:

          【解决方案5】:

          这是对@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()
              }
          }
          

          【讨论】:

          • 这很好用,但我有一个 tintColor,这会将它变成黑色。你知道我怎样才能保持当前的 tintColor 吗?
          • 我最终只是为颜色单独添加了另一个 CABasicAnimation,这似乎可以完成这项工作。
          【解决方案6】:

          这里很快:

            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"))
          

          【讨论】:

          • 太棒了!谢谢!一句话:我在 func self.setImage(newImage, for: .normal) 中添加了最后一行。第二次按下按钮是必要的
          【解决方案7】:

          看来你要找的是这个。它在 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];
          

          【讨论】:

          • 感谢有关使用 Core Animation 的迷你课程!
          • 出于好奇,您为什么选择将removedOnCompletion 设置为NO?
          • @RileyAvron 这样做是为了确保动画不会在最后恢复。说实话,我不确定它是否 100% 需要,因为无论如何我们都将 newImage 设置为 Button 的图像......但我通常总是将它添加到那里以确保安全
          【解决方案8】:

          您可以尝试像这样转换 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;
              }];
          }];
          

          【讨论】:

          • 这行得通,但我不明白为什么。你愿意用动画图像解释第二部分吗?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-24
          • 1970-01-01
          • 1970-01-01
          • 2019-02-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多