Verblassen / Auflösen beim Ändern des UIImageView-Bildes

160

Anstatt zwei zu erstellen UIImageViews, erscheint es logisch, einfach die imageeiner Ansicht zu ändern . Wenn ich das mache, gibt es dann eher eine Überblendung zwischen den beiden Bildern als einen sofortigen Wechsel?

Josh Kahane
quelle
1
@ kumar-kl Ihre Bearbeitung hat ein wichtiges Tag entfernt. Bitte tu das nicht.
Eric Aya
1
@KumarKL Aber hier ist "Objective-C" kein Tag mit niedriger Priorität! Entfernen Sie es nicht nur, um "schnell" hinzuzufügen, dies macht keinen Sinn, es ist tatsächlich Grenzvandalismus ...
Eric Aya
1
@EricD, Ok, ich werde das nicht wiederholen. Dank für Ihr Interesse.
Kumar KL

Antworten:

45

Bearbeiten: Es gibt eine bessere Lösung von @algal unten .

Eine andere Möglichkeit, dies zu tun, ist die Verwendung vordefinierter CAAnimation-Übergänge:

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;

Weitere Informationen finden Sie im Beispielprojekt "View Transitions" von Apple: https://developer.apple.com/library/content/samplecode/ViewTransitions/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007411

Mirkules
quelle
1
Perfekt! Ich füge einen Teil dieses Codes der Kategorie UIImageView (WebCache) von SDWebImage hinzu.
Autobots
@OutMan Sie könnten besser dran sein, wenn Sie die neuere Methode von user577888 verwenden.
Mirkules
Ich setze mein Bild auch nach einem SDWebImages-Rückruf auf diese Weise, aber aus irgendeinem Grund ist das Bild der ersten Zelle in meiner CollectionViewCell zunächst das Bild der letzten sichtbaren Zelle, wenn alle meine Zellen aktualisiert werden. Ich denke, es ist eine Art Caching der Präsentationsschicht oder so?!? Irgendwelche Ideen, was es sein könnte?
Georg
Upvote für die Bearbeitung "Es gibt eine bessere Lösung von @algal unten."
Rob
581

Mit den neuen blockbasierten UIKit animationMethoden kann es viel einfacher sein .

Angenommen, der folgende Code befindet sich im Ansichts-Controller, und die UIImageView, die Sie auflösen möchten, ist eine Unteransicht von self.view, die über die Eigenschaft adressierbar ist. self.imageViewDann benötigen Sie lediglich :

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

Getan.

Und um es in Swift zu tun, ist es so:

    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 & 5

     let toImage = UIImage(named:"myname.png")
     UIView.transition(with: self.imageView,
                       duration: 0.3,
                       options: .transitionCrossDissolve,
                       animations: {
                           self.imageView.image = toImage
                       },
                       completion: nil)
Algen
quelle
3
Die anderen Antworten sind korrekt, aber veraltet (und / oder zu ausführlich).
Steven Kramer
3
Es ist nicht notwendig, den Übergang in der Superansicht durchzuführen. Ich habe es geschafft, dass dies funktioniert, indem ich UIImageView selbst als Ziel angegeben habe.
Desmond
7
@ user577888 nur eine kleine Sache. Sie sollten null an den leeren Abschlussblock übergeben. Blöcke sind keine Funktionszeiger (wie durch ^ gekennzeichnet) und funktionieren wie ein Objektiv-c-Objekt. Wenn Sie NULL übergeben, interpretiert der Compiler dies entweder als 0 oder (void *) 0. Wenn der zugrunde liegende Code für TransitionWithView: ... aus irgendeinem Grund versehentlich eine Nachricht an den Abschlussblock sendet (z. B. [Abschlusskopie]), ohne dessen Gültigkeit zu überprüfen, führt dies zu einem Fehler. Sie sollten also immer die Null von Objective-C verwenden, wenn Sie einen Block auf leer setzen.
Herr T
3
@ Mr.T NULL und nil sind im Wert identisch. Beide sind auf 0 definiert und es ist unwahrscheinlich, dass sich etwas ändert. Daher ist es sicher, NULL überall dort zu verwenden, wo Sie Null verwenden würden oder könnten.
Ashevin
1
@ Mr.T Mein Punkt ist, dass die Verwendung übereinander niemals zu einem Absturz führen wird, da sie auf der Ebene des kompilierten Codes identisch sind und aus praktischen Gründen immer identisch sein werden. Das Unterdrücken von Compiler-Warnungen ist im Allgemeinen eine gute Idee, aber es ist einfach falsch, den Leuten zu sagen, dass es ein Fehler ist, NULL anstelle von Null zu verwenden.
Ashevin
6

Ja, was Sie sagen, ist absolut richtig und das ist der Weg, es zu tun. Ich habe diese Methode geschrieben und verwende sie immer, um mein Bild auszublenden. Ich beschäftige mich CALayerdamit. Dazu müssen Sie Core Animation importieren.

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

Sie können das Gegenteil tun, um ein Bild auszublenden. Nachdem es ausgeblendet ist. Sie entfernen es einfach aus der Übersicht (was ist UIImageView). [imageView removeFromSuperview].

Srikar Appalaraju
quelle
Ich füge diesen Code hinzu, nachdem ich ein Bild in UIImageView gesetzt habe. Es scheint, dass beim Starten der Animation ein Blinken auftritt.
Autobots
4

Sie können die Einblendfunktion auch in eine Unterklasse packen, um sie dann wie im folgenden Beispiel als allgemeine UIImageView zu verwenden:

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

Eine mögliche Implementierung folgt.

Hinweis: Die Art und Weisen Sie tatsächlich die Fade-in implementieren in der setImage:Funktion kann, ändern und eine der anderen hervorragenden Beispiele in den anderen Antworten auf diese Frage beschrieben werden könnten - eine zusätzliche on-the-fly zu schaffen , UIImageViewwie ich bin hier Macht zu tun in Ihrer spezifischen Situation ein inakzeptabler Aufwand sein .

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

Der obige Code basiert auf einigen Annahmen (einschließlich der Aktivierung von ARC in Ihrem XCode-Projekt), ist nur als Proof of Concept gedacht und bleibt im Interesse der Klarheit und Fokussierung relevant, indem wichtiger nicht verwandter Code weggelassen wird. Bitte kopieren Sie es nicht einfach blind.

Magma
quelle
3

Ich brauchte den Übergang, um ihn auf unbestimmte Zeit zu wiederholen. Es dauerte eine Menge Versuch und Irrtum für diesen, aber ich bekam endlich das Endergebnis, das ich suchte. Dies sind Codefragmente zum Hinzufügen von Bildanimationen zu einer UIImageView in einer UITableViewCell.

Hier ist der relevante Code:

@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;
}
Christopher
quelle
Hallo, ich habe mich gefragt, ob Sie weitere Informationen zu Ihrem [self setVarietyImageView: cell.imageView] hinzufügen könnten. Methode, wie ich die letzte Zelle zum Animieren oder alle zum Animieren bringen kann, aber sehr schnell, danke
gav
Hallo Gav, "VarietéImageView" ist eine schwache Referenz im View Controller, so dass ich cell.imageView zuweisen und später in der Methode 'animateImages' darauf verweisen kann. @property (nichtatomar, schwach) UIImageView *varietätImageView; Sie können die Bilder schneller drehen lassen, indem Sie in "TransitionWithView" eine kürzere "Dauer" festlegen. Hoffentlich ist es das, was Sie fragen.
Christopher
Hallo Christopher, danke für die Antwort. Ich habe mich über die "setVarietyImageView" gewundert: Ich gehe davon aus, dass es sich um eine Art Void-Methode handelt, die die Wiederverwendung ermöglicht, da ich nur die letzte Zelle animieren konnte. Nochmals vielen Dank für die Beantwortung, alles Gute Gav
gav
Diese Methode wird mit der Standarddeklaration "Eigenschaft" generiert. Zum Beispiel @property (nichtatomar, schwach) UIImageView * VarietéImageView. Es ist eine "schwache" Referenz, da sie auf eine andere lokale Variable verweist (die Bildansicht der Tabellenzelle). Ich hätte stattdessen auf die Tabellenzelle verweisen und auf die cell.imageView in der Methode animateImages zugreifen können. Ich hoffe das hilft.
Christopher
2

Nachdem ich UIView.transition()mit der .transitionCrossDissolveOption herumgespielt und Probleme mit der Option festgestellt hatte (ich habe versucht, Bilder zu animieren, die sich in einer UIImageView ändern, und der Übergang erfolgte sofort ohne Animation), stellte ich fest, dass Sie nur eine weitere Option hinzufügen müssen, mit der Sie Eigenschaften animieren können, die sich in der Ansicht ändern ( Swift 4.2 ):

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

Außerdem: Wenn Ihre Bildansicht Unteransichten enthält, wird diese ebenfalls neu gezeichnet und kann Animationen verhindern. Zum Beispiel hatte ich eine Unteransicht mit Unschärfe in meiner Bildansicht und in diesem Fall funktioniert die Animation nicht. Also habe ich einfach meine Ansichtshierarchie geändert und die Unschärfe in eine eigene Ansicht verschoben und über imageView platziert.

Pavel
quelle
0

Dies ist meiner Meinung nach der kürzeste Weg. Erstellen Sie eine UIView-Animation und schreiben Sie sie in Ihre imageView.

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

Durch die Verwendung der highlightedImageEigenschaft kann dies etwas einfacher gemacht werden. Hier ist ein Beispiel in Swift 3. Stellen Sie zuerst sowohl das normale als auch das hervorgehobene Bild ein:

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

Und wenn Sie zwischen diesen animierten wechseln möchten:

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