web-dev-qa-db-fra.com

Fondu/dissoudre lors de la modification de l'image de UIImageView

Plutôt que de créer deux UIImageViews, il semble logique de simplement changer la image d'une vue. Si je le fais, y a-t-il un fondu/fondu entre les deux images plutôt qu’un commutateur instantané?

152
Josh Kahane

Edit: il existe une meilleure solution de @algal ci-dessous .

Pour ce faire, vous pouvez également utiliser des transitions CAAnimation prédéfinies:

CATransition *transition = [CATransition animation];
transition.duration = 0.25;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;
transition.delegate = self;
[self.view.layer addAnimation:transition forKey:nil];
view1.hidden = YES;
view2.hidden = NO;

Voir le projet exemple View Transitions d'Apple: https://developer.Apple.com/library/content/samplecode/ViewTransitions/Introduction/Intro.html#//Apple_ref/doc/uid/DTS40007411

43
Mirkules

Il peut être beaucoup plus simple d'utiliser les nouvelles méthodes d'animation UIKit basées sur des blocs.

Supposons que le code suivant se trouve dans le contrôleur de vue et que le UIImageView que vous voulez dissoudre de manière croisée soit une sous-vue de self.view adressable via la propriété self.imageView. Alors tout ce dont vous avez besoin est:

UIImage * toImage = [UIImage imageNamed:@"myname.png"];
[UIView transitionWithView:self.imageView
                  duration:5.0f
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                  self.imageView.image = toImage;
                } completion:nil];

Terminé.

Et pour le faire à Swift, c'est comme ça:

let toImage = UIImage(named:"myname.png")
UIView.transitionWithView(self.imageView,
                          duration:5,
                          options: UIViewAnimationOptions.TransitionCrossDissolve,
                          animations: { self.imageView.image = toImage },
                          completion: nil)

Swift 3.0

 let toImage = UIImage(named:"myname.png")
 UIView.transition(with: self.imageView,
                   duration: 0.3,
                   options: .transitionCrossDissolve,
                   animations: {
                       self.imageView.image = toImage
                   },
                   completion: nil)
565
algal

Oui, ce que vous dites est absolument correct et c’est la meilleure façon de le faire. J'ai écrit cette méthode et l'utilise toujours pour se fondre dans mon image. Je traite avec CALayer pour cela. Vous devez importer Core Animation pour cela. 

+ (void)fadeInLayer:(CALayer *)l
{
    CABasicAnimation *fadeInAnimate   = [CABasicAnimation animationWithKeyPath:@"opacity"];
    fadeInAnimate.duration            = 0.5;
    fadeInAnimate.repeatCount         = 1;
    fadeInAnimate.autoreverses        = NO;
    fadeInAnimate.fromValue           = [NSNumber numberWithFloat:0.0];
    fadeInAnimate.toValue             = [NSNumber numberWithFloat:1.0];
    fadeInAnimate.removedOnCompletion = YES;
    [l addAnimation:fadeInAnimate forKey:@"animateOpacity"];
    return;
}

Vous pouvez faire le contraire pour fondre une image. Après qu'il s'estompe. Vous venez de le supprimer de Superview (qui est UIImageView). [imageView removeFromSuperview].

6

Pour Swift 3.0.1:

UIView.transition(with: self.imageView,
              duration:0.5,
              options: .transitionCrossDissolve,
              animations: { self.imageView.image = newImage },
              completion: nil)

Référence: https://Gist.github.com/licvido/bc22343cacfa3a8ccf88

6
Sour LeangChhean

Vous pouvez également conditionner la fonctionnalité d'ouverture en fondu dans une sous-classe, de sorte que vous puissiez ensuite l'utiliser en tant que UIImageView commun, comme dans l'exemple suivant:

IMMFadeImageView *fiv=[[IMMFadeImageView alloc] initWithFrame:CGRectMake(10, 10, 50, 50)];
[self.view addSubview:fiv];
fiv.image=[UIImage imageNamed:@"initialImage.png"];
fiv.image=[UIImage imageNamed:@"fadeinImage.png"];  // fades in

Une implémentation possible suit. 

Remarque: la manière dont vous implémentez le fondu dans la fonction setImage: peut changer et pourrait constituer l'un des autres excellents exemples décrits dans les autres réponses à cette question: créer une variable supplémentaire à la volée UIImageView comme I ' faire ici pourrait être une surcharge inacceptable dans votre situation particulière.

IMMFadeImageView.h :

#import <UIKit/UIKit.h>

@interface IMMFadeImageView : UIImageView
@property (nonatomic,assign) float fadeDuration;
@end

IMMFadeImageView.m :

#import "IMMFadeImageView.h"

@implementation IMMFadeImageView
@synthesize fadeDuration;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.fadeDuration=1;
    }
    return self;
}
-(void)setImage:(UIImage *)newImage{

    if(!self.image||self.fadeDuration<=0){
        super.image=newImage;
    } else {
        UIImageView *iv=[[UIImageView alloc] initWithFrame:self.bounds];
        iv.contentMode=self.contentMode;
        iv.image=super.image;
        iv.alpha=1;
        [self addSubview:iv];
        super.image=newImage;
        [UIView animateWithDuration:self.fadeDuration delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
            iv.alpha=0;
        } completion:^(BOOL finished) {
            [iv removeFromSuperview];
        }];
    }
}

Le code ci-dessus repose sur quelques hypothèses (y compris l'activation d'ARC dans votre projet XCode), est uniquement conçu comme une preuve de concept et, dans un souci de clarté et de pertinence, il reste pertinent en omettant le code important sans rapport. S'il vous plaît ne faites pas simplement un copier-coller à l'aveugle.

5
magma

J'avais besoin de la transition pour se répéter indéfiniment. Il a fallu BEAUCOUP d’essais et d’erreur pour celui-ci, mais j’ai finalement obtenu le résultat final que je cherchais. Ce sont des extraits de code permettant d'ajouter une animation d'image à un UIImageView dans un UITableViewCell.

Voici le code pertinent:

@interface SomeViewController ()
@property(nonatomic, strong) NSMutableArray *imagesArray;
@property(nonatomic, assign) NSInteger varietyImageAnimationIndex;
@property(nonatomic, assign) BOOL varietyImagesAnimated;
@end

@implementation SomeViewController
@synthesize imagesArray;
@synthesize varietyImageAnimationIndex;
@synthesize varietyImagesAnimated;
...

// NOTE: Initialize the array of images in perhaps viewDidLoad method.

-(void)animateImages
{
    varietyImageAnimationIndex++;

    [UIView transitionWithView:varietyImageView
                      duration:2.0f
                       options:UIViewAnimationOptionTransitionCrossDissolve
                    animations:^{
                        varietyImageView.image = [imagesArray objectAtIndex:varietyImageAnimationIndex % [imagesArray count]];
                    } completion:^(BOOL finished) {
                        [self animateImages];
                    }];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   ...
        [cell.imageView setImage:[imagesArray objectAtIndex:0]];


        [self setVarietyImageView:cell.imageView];

        if (! varietyImagesAnimated)
        {
            varietyImagesAnimated = YES;
            [self animateImages];
        }

    ...
    return cell;
}
3
Christopher

Après avoir joué avec UIView.transition() et rencontré des problèmes avec l'option .transitionCrossDissolve (j'essayais d'animer des images qui changeaient dans un UIImageView et la transition se produisait instantanément sans animation), j'ai découvert qu'il vous suffisait d'ajouter une option supplémentaire permettant d'animer les propriétés vue ( Swift 4.2 ):

UIView.transition(with: self.imageView,
                   duration: 1,
                   options: [.allowAnimatedContent, .transitionCrossDissolve],
                   animations: { self.imageView.image = newImage },
                   completion: nil)

De plus: si vous avez des sous-vues sur votre imageView, celle-ci sera également redessinée et cela pourrait empêcher l'animation. Par exemple, j'avais une sous-vue avec un flou sur mon imageView et dans ce cas l'animation ne fonctionnait pas. Donc, je viens de changer ma hiérarchie de vues et de déplacer le flou vers sa propre vue et de le placer sur imageView.

0
Pavel

En utilisant la propriété highlightedImage, cela peut être un peu plus simple. Voici un exemple dans Swift 3. Commencez par définir les images normales et en surbrillance:

let imageView = UIImageView(image: UIImage(named: "image"), highlightedImage: UIImage(named: "highlightedImage"))

Et quand vous voulez changer entre ceux animés:

UIView.transition(with: imageView, duration: 0.3, options: .transitionCrossDissolve, animations: { self.imageView.isHighlighted = !self.imageView.isHighlighted}, completion: .none)
0
Jens Schwarzer

C'est, je pense, le moyen le plus court de le faire. Créez une animation UIView et validez-la sur votre imageView.

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[myImageView setAlpha:0.0];
[UIView commitAnimations];
0
divyenduz