Dissolvenza / dissolvenza quando si cambia l'immagine di UIImageView


160

Invece di crearne due UIImageViews, sembra logico semplicemente cambiare la imagevista di una. Se lo faccio, c'è comunque una dissolvenza dissolvenza / croce tra le due immagini piuttosto che un passaggio istantaneo?


1
@ kumar-kl La tua modifica ha rimosso un tag importante. Per favore, non farlo.
Eric Aya,

1
@KumarKL Ma qui "goal-c" non è un tag a bassa priorità! Non rimuoverlo solo per aggiungere "veloce", questo non ha senso, in realtà è un vandalismo limite ...
Eric Aya,

1
@EricD, Ok non ripeterò lo stesso. Grazie per la tua preoccupazione.
Kumar KL,

Risposte:


45

Modifica: di seguito è disponibile una soluzione migliore da @algal .

Un altro modo per farlo è utilizzare le transizioni CAAnimation predefinite:

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;

Vedi il progetto di esempio View Transitions di Apple: https://developer.apple.com/library/content/samplecode/ViewTransitions/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007411


1
Perfetto! Aggiungo parte di questo codice nella categoria UIImageView (WebCache) di SDWebImage.
Autobot

@OutMan potresti essere migliore usando il metodo più recente di seguito da user577888.
Mirkules,

Sto anche impostando la mia immagine dopo un callback SDWebImages in quel modo, ma per qualche ragione nel mio CollectionViewCell l'immagine della prima cella, inizialmente è quella dell'ultima cella visibile se tutte le mie celle si aggiornano. Immagino sia una specie di memorizzazione nella cache della presentazione Layer o qualcosa del genere?!? Qualche idea su cosa potrebbe essere?
Georg,

Upgrade per la modifica "di seguito è disponibile una soluzione migliore da @algal".
Rob

581

Può essere molto più semplice usando i nuovi UIKit animationmetodi basati su blocchi .

Supponiamo che il seguente codice sia nel controller di visualizzazione e che UIImageView che si desidera dissolvere in modo incrociato sia una sottoview di self.view indirizzabile tramite la proprietà self.imageViewQuindi tutto ciò che serve è:

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

Fatto.

E farlo in Swift, è così:

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

Swift 3, 4 e 5

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

3
Le altre risposte sono corrette ma obsolete (e / o eccessivamente dettagliate).
Steven Kramer,

3
Non è necessario eseguire la transizione sulla super vista. Sono riuscito a farlo funzionare specificando UIImageView stesso come destinazione.
Desmond,

7
@ user577888 solo una piccola cosa. Dovresti passare zero al blocco di completamento vuoto. I blocchi non sono puntatori di funzioni (come indicato da ^) e funzionano come un oggetto c-obiettivo. Se passi NULL, il compilatore lo interpreterà come 0 o (void *) 0. Se per qualche motivo il codice sottostante per transitWithView: ... invia accidentalmente un messaggio al blocco di completamento (ad es. [Copia di completamento]) senza verificarne la validità, ciò comporterà un errore. Quindi dovresti sempre usare zero di goal-c quando si imposta un blocco su vuoto.
Mr. T

3
@ Mr.T NULL e zero hanno un valore identico. Entrambi sono definiti su 0 e nessuno dei due potrà mai cambiare. Quindi, è sicuro usare NULL ovunque tu voglia o potresti usare zero.
ashevin,

1
@ Mr.T Il mio punto è che l'uso l'uno dell'altro non causerà mai un arresto anomalo perché a livello di codice compilato sono identici e, per motivi pratici, lo saranno sempre. Sopprimere gli avvisi del compilatore è una buona idea, in generale, ma dire alla gente che è un errore usare NULL invece di zero è semplicemente sbagliato.
ashevin,


6

Sì, quello che dici è assolutamente corretto e questo è il modo di farlo. Ho scritto questo metodo e lo uso sempre per Dissolvenza nella mia immagine. Mi occupo CALayerdi questo. Per questo è necessario importare Core Animation.

+ (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;
}

Potresti fare il contrario per Dissolvenza di un'immagine. Dopo che svanisce. Lo rimuovi da Superview (che è UIImageView). [imageView removeFromSuperview].


Aggiungo questo codice dopo aver impostato un'immagine in UIImageView, sembra che ci sia un battito di ciglia quando si avvia l'animazione.
Autobot

4

È inoltre possibile impacchettare la funzionalità di dissolvenza in una sottoclasse, in modo da poterla utilizzare come UIImageView comune, come nell'esempio seguente:

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

Segue una possibile implementazione.

Nota: il modo in cui implementate la dissolvenza nella setImage:funzione può cambiare e potrebbe essere uno degli altri eccellenti esempi descritti nelle altre risposte a questa domanda: la creazione di un ulteriore al volo UIImageViewcome sto facendo qui potrebbe essere un sovraccarico inaccettabile nella tua situazione specifica .

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];
        }];
    }
}

Il codice sopra riportato si basa su alcuni presupposti (incluso l'ARC abilitato nel progetto XCode), è inteso solo come una prova del concetto e, nell'interesse della chiarezza e dell'attenzione, rimane rilevante omettendo un codice non correlato importante. Per favore non copiarlo e incollarlo alla cieca.


3

Avevo bisogno che la transizione si ripetesse indefinitamente. Ci sono volute molte prove ed errori per questo, ma alla fine ho ottenuto il risultato finale che stavo cercando. Questi sono frammenti di codice per l'aggiunta di animazioni di immagini a UIImageView in UITableViewCell.

Ecco il codice pertinente:

@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;
}

Ciao, mi chiedevo se potessi aggiungere qualche informazione in più su [self setVarietyImageView: cell.imageView]; come posso ottenere l'ultima cella da animare o tutta da animare ma davvero veloce, grazie
gav

Salve Gav, "varietàImageView" è un riferimento debole nel controller di visualizzazione in modo che io possa assegnare a cell.imageView e fare riferimento in un secondo momento nel metodo "animateImages". @property (nonatomic, debole) UIImageView * varietàImageView; È possibile rendere le immagini più veloci ruotando impostando una "durata" più breve in "transizioneWithView". Spero che questo sia quello che stai chiedendo.
Christopher,

Ciao Christopher, grazie per la risposta, mi chiedevo "setVarietyImageView:" Presumo che sia un qualche tipo di metodo vuoto che consente il riutilizzo poiché sono stato in grado di animare solo l'ultima cella. Ancora una volta vi ringrazio per la risposta, tutti i migliori Gav
GAV

Questo metodo viene generato utilizzando la dichiarazione "proprietà" standard. Ad esempio, @property (nonatomico, debole) UIImageView * varietyImageView. È un riferimento "debole" in quanto si riferisce a un'altra variabile locale (imageView della cella della tabella). Avrei potuto invece fare un riferimento alla cella della tabella e accedere a cell.imageView nel metodo animateImages. Spero che aiuti.
Christopher

2

Dopo aver giocato UIView.transition()e avuto problemi con l' .transitionCrossDissolveopzione (stavo cercando di animare le immagini cambiando all'interno di una UIImageView e la transizione si è verificata istantaneamente senza animazione) ho scoperto che devi solo aggiungere un'altra opzione che ti consente di animare le proprietà cambiando all'interno della vista ( Swift 4.2 ):

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

Inoltre: se hai delle visualizzazioni secondarie su imageView, anche questa verrà ridisegnata e potrebbe impedire l'animazione. Ad esempio, ho avuto una subview con sfocatura sul mio imageView e in tal caso l'animazione non funziona. Quindi ho appena cambiato la mia gerarchia di visualizzazione e ho spostato la sfocatura nella sua vista e l'ho messa su imageView.


0

Questo è il modo più breve per farlo. Crea un'animazione UIView e esegui il commit su imageView.

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

0

Usando la highlightedImageproprietà questo può essere reso un po 'più semplice. Ecco un esempio in Swift 3. Innanzitutto imposta sia l'immagine normale che quella evidenziata:

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

E quando vuoi cambiare tra quelli animati:

UIView.transition(with: imageView, duration: 0.3, options: .transitionCrossDissolve, animations: { self.imageView.isHighlighted = !self.imageView.isHighlighted}, completion: .none)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.