Como animar a alteração de imagem em um UIImageView?

199

Eu tenho um UIImageViewcom uma imagem. Agora eu tenho uma imagem completamente nova (arquivo gráfico) e quero exibi-la nisso UIImageView. Se eu apenas definir

myImageView.image = newImage;

a nova imagem é visível imediatamente. Não é animador.

Eu quero que desapareça bem na nova imagem. Eu pensei que talvez haja uma solução melhor do que apenas criar um novo UIImageViewem cima disso e misturar-se com animação?

dontWatchMyProfile
fonte

Respostas:

260

Não tenho certeza se é possível animar UIViews com efeito fade, pois todas as transições de exibição suportadas são definidas na UIViewAnimationTransitionenumeração. O efeito de desbotamento pode ser alcançado usando o CoreAnimation. Exemplo de exemplo para esta abordagem:

#import <QuartzCore/QuartzCore.h>
...
imageView.image = [UIImage imageNamed:(i % 2) ? @"3.jpg" : @"4.jpg"];

CATransition *transition = [CATransition animation];
transition.duration = 1.0f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;

[imageView.layer addAnimation:transition forKey:nil];
Vladimir
fonte
2
Seu código funcionou perfeitamente ao passar de uma imagem para outra. Você sabe como fazê-lo funcionar com animação automática de imagens em um UIImageView (propriedade animationImages)?
CedricSoubrie
Você pode tentar usar CAKeyFrameAnimation para a propriedade de conteúdo da camada, sem ter certeza se o efeito será o mesmo. Ou defina delegar animação e, na função delegar retorno de chamada, comece a animar para a próxima imagem quando a animação anterior terminar.
Vladimir
2
Definitivamente, isso é mais simples do que o crossfading manual de uma visualização de imagem separada. Obrigado!
Kevlar
Bem. Se o quadro de visualização de imagens mudar, ele permanecerá na mesma posição.
Hfossli 26/09/12
@ Fossli, você quer dizer quando o quadro muda durante a animação? Essa é uma pergunta diferente
Vladimir
368
[UIView transitionWithView:textFieldimageView
                  duration:0.2f
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                    imageView.image = newImage;
                } completion:nil];

é outra possibilidade

Ilker Baltaci
fonte
1
simples e abre toda uma gama de outros efeitos de animação entre as imagens.
Então Over It
1
Tem o mesmo problema que @hfossli mencionou em relação às alterações de quadro. A animação seria lenta se os layouts fossem alterados durante isso.
Geva
1
Esta é a melhor solução, porque pode ser combinada com outras animações.
Kelin
161

Nas palavras de Michael Scott, seja simples e estúpido. Aqui está uma maneira simples de fazer isso no Swift 3 e Swift 4 :

UIView.transition(with: imageView,
                  duration: 0.75,
                  options: .transitionCrossDissolve,
                  animations: { self.imageView.image = toImage },
                  completion: nil)
Zia
fonte
3
Funciona como um encanto. Obrigado!
RobertoAllende
1
Uau, ótimo! Não sabia sobre esta droga por muito tempo :)
sabiland
1
Isso mudará para 1 imagem. e se eu tiver uma matriz de imagens e quiser mostrar uma por uma com animação de transição?
Ammar Mujeeb 14/01
1
Você pode usar o bloco de conclusão para fazer a transição para o próximo.
Zia
41

Aqui está um exemplo no Swift que primeiro dissolve uma nova imagem e depois adiciona uma animação saltitante:

var selected: Bool {
  willSet(selected) {
    let expandTransform:CGAffineTransform = CGAffineTransformMakeScale(1.15, 1.15);
    if (!self.selected && selected) {
      UIView.transitionWithView(self.imageView,
        duration:0.1,
        options: UIViewAnimationOptions.TransitionCrossDissolve,
        animations: {
          self.imageView.image = SNStockCellSelectionAccessoryViewImage(selected)
          self.imageView.transform = expandTransform
        },
        completion: {(finished: Bool) in
          UIView.animateWithDuration(0.4,
            delay:0.0,
            usingSpringWithDamping:0.40,
            initialSpringVelocity:0.2,
            options:UIViewAnimationOptions.CurveEaseOut,
            animations: {
              self.imageView.transform = CGAffineTransformInvert(expandTransform)
            }, completion:nil)
      })
    }
  }
}

var imageView:UIImageView

Se imageViewfor adicionado corretamente à visualização como uma subvisão, alternar entre selected = falsepara selected = truedeve trocar a imagem por uma animação insuficiente. SNStockCellSelectionAccessoryViewImageapenas retorna uma imagem diferente com base no estado de seleção atual, veja abaixo:

private let SNStockCellSelectionAccessoryViewPlusIconSelected:UIImage = UIImage(named:"PlusIconSelected")!
private let SNStockCellSelectionAccessoryViewPlusIcon:UIImage = UIImage(named:"PlusIcon")!

private func SNStockCellSelectionAccessoryViewImage(selected:Bool) -> UIImage {
  return selected ? SNStockCellSelectionAccessoryViewPlusIconSelected : SNStockCellSelectionAccessoryViewPlusIcon
}

O exemplo GIF abaixo é um pouco mais lento, a animação real acontece mais rapidamente:

                                       Animação de salto UIImageView Gif

Zorayr
fonte
16

Código:

var fadeAnim:CABasicAnimation = CABasicAnimation(keyPath: "contents");

fadeAnim.fromValue = firstImage;
fadeAnim.toValue   = secondImage;
fadeAnim.duration  = 0.8;         //smoothest value

imageView.layer.addAnimation(fadeAnim, forKey: "contents");

imageView.image = secondImage;

Exemplo:

Exemplo UIImageView do código

Solução mais detalhada e divertida : ( Alternando uma torneira )

    let fadeAnim:CABasicAnimation = CABasicAnimation(keyPath: "contents");

    switch imageView.image {
        case firstImage?:
            fadeAnim.fromValue = firstImage;
            fadeAnim.toValue   = secondImage;
            imageView.image    = secondImage;
        default:
            fadeAnim.fromValue = secondImage;
            fadeAnim.toValue   = firstImage;
            imageView.image    = firstImage;
    }

    fadeAnim.duration = 0.8;

    imageView.layer.addAnimation(fadeAnim, forKey: "contents");
J-Dizzle
fonte
10

Tente o seguinte:

_imageView.image = image;
[_imageView.layer addAnimation:[CATransition animation] forKey:kCATransition];
Peter Stajger
fonte
swift: _imageView.layer.addAnimation (CATransition (), forKey: kCATransition) #
Eugene Braginets
8

Com Swift 3

extension UIImageView{   
 var imageWithFade:UIImage?{
        get{
            return self.image
        }
        set{
            UIView.transition(with: self,
                              duration: 0.5, options: .transitionCrossDissolve, animations: {
                                self.image = newValue
            }, completion: nil)
        }
    }
}

Uso:

myImageView.imageWithFade = myImage
M.Nadeeshan
fonte
6

Por que não tentar isso?

NSArray *animationFrames = [NSArray arrayWithObjects:
  [UIImage imageWithName:@"image1.png"],
  [UIImage imageWithName:@"image2.png"], 
  nil];

UIImageView *animatedImageView = [[UIImageView alloc] init];
animatedImageView.animationImages = animationsFrame;
[animatedImageView setAnimationRepeatCount:1];
[animatedImageView startAnimating];

Uma versão rápida:

let animationsFrames = [UIImage(named: "image1.png"), UIImage(named: "image2.png")]
let animatedImageView = UIImageView()
animatedImageView.animationImages = animationsFrames
animatedImageView.animationRepeatCount = 1
animatedImageView.startAnimating()
William Hu
fonte
Isso define o UIImageView para repetir a alternância para sempre ... o autor estava apenas pedindo uma alteração :(
J-Dizzle
setAnimationRepeatCount
William Hu
SetAnimationRepeatCount não altera nada. Ele nunca para
Yucel Bayram
5
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:@"contents"];
fadeAnim.fromValue = (__bridge id)imageView.image.CGImage;
fadeAnim.toValue = (__bridge id)[UIImage imageNamed:@"newImage.png"].CGImage;
fadeAnim.duration = 2.0;
[imageView.layer addAnimation:fadeAnim forKey:@"contents"];
imageView.layer.contents = (__bridge id)[UIImage imageNamed:@"newImage.png"].CGImage;
kas-kad
fonte
3

Existem algumas abordagens diferentes aqui: UIAnimations para minha lembrança, parece o seu desafio.

Edit: com preguiça de mim :)

No post, eu estava me referindo a este método:

[newView setFrame:CGRectMake( 0.0f, 480.0f, 320.0f, 480.0f)]; //notice this is OFF screen!
[UIView beginAnimations:@"animateTableView" context:nil];
[UIView setAnimationDuration:0.4];
[newView setFrame:CGRectMake( 0.0f, 0.0f, 320.0f, 480.0f)]; //notice this is ON screen!
[UIView commitAnimations];

Mas, em vez de animar o quadro, você anima o alfa:

[newView setAlpha:0.0]; // set it to zero so it is all gone.
[UIView beginAnimations:@"animateTableView" context:nil];
[UIView setAnimationDuration:0.4];
[newView setAlpha:0.5]; //this will change the newView alpha from its previous zero value to 0.5f
[UIView commitAnimations];
RickiG
fonte
2

No iOS 5, este é muito mais fácil:

[newView setAlpha:0.0];
[UIView animateWithDuration:0.4 animations:^{
    [newView setAlpha:0.5];
}];
Borut Tomazin
fonte
4
Isso não ajuda o problema original, o que é que você tem uma imagem já apresentada, e quer cross-fade para uma nova imagem ...
Kendall Helmstetter Gelner
4
certo .. esta resposta não resolve a questão. A questão não era como desaparecer na visualização de imagens, mas desaparecer de uma imagem antiga para uma nova imagem. Blocos de animação foram introduzidos no iOS 4.
Bastian
2

Swift 4 Isso é incrível

  self.imgViewPreview.transform = CGAffineTransform(scaleX: 0, y: 0)
          UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0, options: .curveEaseOut, animations: {
              self.imgViewPreview.image = newImage
              self.imgViewPreview.transform = .identity
          }, completion: nil)
Gurjinder Singh
fonte
1

A resposta de Vladimir é perfeita, mas qualquer pessoa como eu está procurando uma solução rápida

Esta solução é trabalhada para a versão rápida 4.2

var i = 0
    func animation(){
        let name = (i % 2 == 0) ? "1.png" : "2.png"
        myImageView.image = UIImage.init(named: name)
        let transition: CATransition = CATransition.init()
        transition.duration = 1.0
        transition.timingFunction = CAMediaTimingFunction.init(name: .easeInEaseOut)
        transition.type = .fade
        myImageView.layer.add(transition, forKey: nil)
        i += 1
    }

Você pode chamar esse método de qualquer lugar. Mudará a imagem para a próxima (imagem) com animação.

Para Swift Versão 4.0, use a solução abaixo

var i = 0
    func animationVersion4(){
        let name = (i % 2 == 0) ? "1.png" : "2.png"
        uiImage.image = UIImage.init(named: name)
        let transition: CATransition = CATransition.init()
        transition.duration = 1.0
        transition.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseInEaseOut)
        transition.type = kCATransitionFade
        uiImage.layer.add(transition, forKey: nil)
        i += 1
    }
Saleh Enam Shohag
fonte