Pudar / bubar saat mengubah gambar UIImageView


160

Daripada membuat dua UIImageViews , tampaknya logis untuk hanya mengubah imagepandangan satu. Jika saya melakukan itu, apakah ada pula yang memiliki fade / cross melarutkan antara dua gambar daripada saklar instan?


1
@ kumar-kl Suntingan Anda menghapus tag penting. Tolong jangan lakukan itu.
Eric Aya

1
@KumarKL Tapi di sini "objektif-c" bukan tag prioritas rendah! Jangan hapus itu hanya untuk menambahkan "cepat", ini tidak masuk akal, itu sebenarnya vandalisme batas ...
Eric Aya

1
@ EricD, Ok saya tidak akan melakukan hal yang sama. Terima kasih atas perhatianmu.
Kumar KL

Jawaban:


45

Sunting: ada solusi yang lebih baik dari @algal di bawah ini .

Cara lain untuk melakukan ini adalah dengan menggunakan transisi CAAnimation yang telah ditentukan:

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;

Lihat proyek contoh Lihat Transisi dari Apple: https://developer.apple.com/library/content/samplecode/ViewTransitions/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007411


1
Sempurna! Saya menambahkan bagian dari kode ini ke dalam kategori UIImageView (WebCache) SDWebImage.
Autobots

@OutMan Anda mungkin lebih baik menggunakan metode yang lebih baru di bawah ini oleh user577888.
Mirkules

Saya juga mengatur gambar saya setelah panggilan balik SDWebImages seperti itu, tetapi untuk beberapa alasan di CollectionViewCell saya gambar sel pertama, awalnya adalah yang dari sel yang terlihat terakhir jika semua sel saya memperbarui. Saya kira itu semacam caching presentasi. Lapisan atau sesuatu?!? Ada ide apa itu?
Georg

Suara positif untuk hasil edit "ada solusi yang lebih baik dari @algal di bawah ini."
Rob

581

Ini bisa jauh lebih sederhana menggunakan berbasis blok baru, UIKit animation metode .

Misalkan kode berikut ada di view controller, dan UIImageView yang ingin Anda belah silang adalah subview dari self.view dialamatkan melalui properti self.imageViewMaka semua yang Anda butuhkan adalah:

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

Selesai

Dan untuk melakukannya di Swift, seperti ini:

    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)

3
Jawaban lainnya benar tetapi sudah usang (dan / atau terlalu bertele-tele).
Steven Kramer

3
Tidak perlu melakukan transisi pada tampilan super. Saya berhasil membuat pekerjaan ini dengan menentukan UIImageView itu sendiri sebagai target.
Desmond

7
@ user577888 hanya hal kecil. Anda harus meneruskan nol ke blok penyelesaian kosong. Blok bukan pointer fungsi (seperti yang dilambangkan oleh ^) dan beroperasi seperti objek objektif-c. Jika Anda melewati NULL, kompiler akan menafsirkannya sebagai 0 atau (void *) 0. Jika karena alasan tertentu kode yang mendasari untuk transisiWithView: ... secara tidak sengaja mengirim pesan ke blok penyelesaian (mis. [Salinan selesai]) tanpa memeriksa validitasnya, ini akan menyebabkan kesalahan. Jadi, Anda harus selalu menggunakan nol objektif-c ketika mengatur blok menjadi kosong.
Tn.

3
@ Mr.T NULL dan nil identik dalam nilainya. Keduanya didefinisikan 0 dan tidak ada yang cenderung berubah. Dengan demikian, aman untuk menggunakan NULL di mana saja Anda mau atau bisa menggunakan nihil.
ashevin

1
@ Mr.T Maksud saya adalah bahwa menggunakan satu di atas yang lain tidak akan pernah menyebabkan crash karena pada tingkat kode yang dikompilasi mereka identik, dan untuk alasan praktis, selalu akan terjadi. Menekan peringatan kompiler adalah ide bagus, secara umum, tetapi memberi tahu orang-orang itu kesalahan untuk menggunakan NULL alih-alih nol sama sekali salah.
ashevin


6

Ya apa yang Anda katakan benar-benar benar dan itulah cara untuk melakukannya. Saya menulis metode ini & selalu menggunakan ini untuk Fade dalam gambar saya. Saya berurusan dengan CALayerini. Anda perlu mengimpor Core Animation untuk ini.

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

Anda bisa melakukan yang sebaliknya untuk memudar gambar. Setelah itu memudar. Anda cukup menghapusnya dari superview (yang UIImageView). [imageView removeFromSuperview].


Saya menambahkan kode ini setelah menetapkan gambar ke UIImageView, sepertinya ada blink ketika memulai animasi.
Autobots

4

Anda juga bisa mengemas fitur fade-in dalam subclass, sehingga Anda bisa menggunakannya sebagai UIImageView yang umum, seperti dalam contoh berikut:

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

Kemungkinan implementasi mengikuti.

Catatan: cara Anda benar-benar mengimplementasikan fade-in pada setImage:fungsi dapat berubah, dan bisa menjadi salah satu contoh bagus lainnya yang dijelaskan dalam jawaban lain untuk pertanyaan ini - membuat on-the-fly tambahan UIImageViewseperti yang saya lakukan di sini mungkin menjadi overhead yang tidak dapat diterima dalam situasi spesifik Anda .

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

Kode di atas bergantung pada beberapa asumsi (termasuk ARC yang diaktifkan dalam proyek XCode Anda), hanya dimaksudkan sebagai bukti konsep, dan demi kejelasan dan fokus, kode tersebut tetap relevan dengan menghilangkan kode penting yang tidak terkait. Tolong jangan hanya copy-paste secara membabi buta.


3

Saya membutuhkan transisi untuk mengulang tanpa batas. Butuh BANYAK percobaan dan kesalahan untuk yang satu ini tetapi saya akhirnya mendapatkan hasil akhir yang saya cari. Ini adalah cuplikan kode untuk menambahkan animasi gambar ke UIImageView di UITableViewCell.

Ini kode yang relevan:

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

Hai Saya bertanya-tanya apakah Anda dapat menambahkan beberapa info lebih lanjut tentang [self setVarietyImageView: cell.imageView]; metode yang saya bisa dapatkan sel terakhir untuk menghidupkan atau semua untuk menghidupkan tetapi sangat cepat, Terima kasih
gav

Hai Gav, "varietyImageView" adalah referensi yang lemah di controller tampilan sehingga saya dapat menetapkan ke cell.imageView dan merujuknya nanti dalam metode 'animateImages'. @property (nonatomik, lemah) UIImageView * varietyImageView; Anda dapat membuat gambar diputar lebih cepat dengan mengatur "durasi" yang lebih pendek di "transitionWithView". Semoga ini yang Anda tanyakan.
Christopher

Halo Christopher, terima kasih atas jawabannya, saya bertanya-tanya tentang "setVarietyImageView:" Saya menganggap itu semacam metode batal yang memungkinkan untuk digunakan kembali karena saya hanya dapat menghidupkan sel terakhir. Sekali lagi Terima kasih telah membalas, semua yang terbaik Gav
gav

Metode ini dihasilkan menggunakan deklarasi "properti" standar. Misalnya, @property (nonatomik, lemah) UIImageView * varietyImageView. Ini referensi "lemah" karena merujuk ke variabel lokal lain (imageView dari sel tabel). Saya malah bisa membuat referensi ke sel tabel dan mengakses cell.imageView dalam metode animateImages. Saya harap ini membantu.
Christopher

2

Setelah bermain-main dengan UIView.transition()dan mendapatkan masalah dengan .transitionCrossDissolveopsi (saya mencoba untuk menganimasikan gambar berubah dalam satu UIImageView dan transisi terjadi secara instan tanpa animasi) Saya menemukan bahwa Anda hanya perlu menambahkan satu opsi lagi yang memungkinkan Anda menghidupkan properti yang berubah di dalam tampilan ( Swift 4.2 ):

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

Selain itu: jika Anda memiliki subview pada imageView Anda, itu akan digambar ulang juga dan itu dapat mencegah animasi. Sebagai contoh, saya memiliki subview dengan blur pada imageView saya dan dalam hal ini animasi tidak berfungsi. Jadi saya baru saja mengubah hierarki tampilan saya dan memindahkan blur ke tampilan sendiri dan meletakkannya di atas imageView.


0

Ini saya pikir cara terpendek untuk melakukannya. Buat animasi UIView dan komit di imageView Anda.

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

0

Dengan menggunakan highlightedImageproperti ini dapat dibuat sedikit lebih sederhana. Berikut ini contoh dalam Swift 3. Pertama-tama atur baik gambar normal maupun yang disorot:

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

Dan ketika Anda ingin mengubah antara animasi tersebut:

UIView.transition(with: imageView, duration: 0.3, options: .transitionCrossDissolve, animations: { self.imageView.isHighlighted = !self.imageView.isHighlighted}, completion: .none)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.