Làm mờ dần / hòa tan khi thay đổi hình ảnh của UIImageView


160

Thay vì tạo hai UIImageViews, có vẻ hợp lý khi chỉ thay đổi imagemột quan điểm. Nếu tôi làm điều đó, có cách nào làm mờ / hòa tan chéo giữa hai hình ảnh thay vì chuyển đổi tức thời không?


1
@ kumar-kl Chỉnh sửa của bạn đã xóa một thẻ quan trọng. Xin đừng làm vậy.
Eric Aya

1
@KumarKL Nhưng ở đây "object-c" không phải là thẻ ưu tiên thấp! Đừng xóa nó chỉ để thêm "swift", điều này vô nghĩa, nó thực sự là phá hoại biên giới ...
Eric Aya

1
@EricD, Ok tôi sẽ không lặp lại như vậy. Cảm ơn sự quan tâm của bạn.
Kumar KL

Câu trả lời:


45

Chỉnh sửa: có một giải pháp tốt hơn từ @acheal bên dưới .

Một cách khác để làm điều này là bằng cách sử dụng các chuyển tiếp CAAnimation được xác định trước:

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;

Xem dự án ví dụ Xem Chuyển tiếp từ Apple: https://developer.apple.com/l Library / content / samplecode / ViewTransitions / Intributiontion / Intro.html


1
Hoàn hảo! Tôi thêm một phần mã này vào danh mục UIImageView (WebCache) của SDWebImage.
Autobots

@OutMan bạn có thể tốt hơn bằng cách sử dụng phương pháp mới hơn bên dưới bởi user577888.
Mirkules

Tôi cũng đang thiết lập hình ảnh của mình sau khi gọi lại SDWebImages theo cách đó, nhưng vì một số lý do trong Bộ sưu tập của tôi, hình ảnh của ô đầu tiên, ban đầu là hình ảnh từ ô hiển thị cuối cùng nếu tất cả các ô của tôi cập nhật. Tôi đoán đó là một số loại bộ nhớ đệm trình bày hoặc một cái gì đó?!? Bất kỳ ý tưởng những gì nó có thể được?
Georg

Upvote cho chỉnh sửa "có một giải pháp tốt hơn từ @acheal bên dưới."
Cướp

581

Nó có thể đơn giản hơn nhiều bằng cách sử dụng các UIKit animationphương thức dựa trên khối mới .

Giả sử đoạn mã sau nằm trong trình điều khiển khung nhìn và UIImageView bạn muốn hòa tan chéo là một khung nhìn của self.view có thể truy cập thông qua thuộc tính self.imageViewSau đó, tất cả những gì bạn cần là:

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

Làm xong.

Và để làm điều đó trong Swift, nó giống như vậy:

    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
Các câu trả lời khác là đúng nhưng lỗi thời (và / hoặc quá dài dòng).
Steven Kramer

3
Không cần thiết phải thực hiện chuyển đổi trên chế độ xem siêu. Tôi đã quản lý để thực hiện công việc này bằng cách chỉ định chính UIImageView là mục tiêu.
Desmond

7
@ user577888 chỉ là chuyện nhỏ. Bạn nên chuyển nil vào khối hoàn thành trống. Các khối không có con trỏ hàm (như được biểu thị bởi ^) và hoạt động như một đối tượng object-c. Nếu bạn vượt qua NULL, trình biên dịch sẽ hiểu là 0 hoặc (void *) 0. Nếu vì một lý do nào đó, mã cơ bản cho quá trình chuyển đổiWithView: ... vô tình gửi tin nhắn đến khối hoàn thành (ví dụ: [bản sao hoàn thành]) mà không kiểm tra tính hợp lệ của nó, điều này sẽ dẫn đến lỗi. Vì vậy, bạn nên luôn luôn sử dụng nil của object-c khi đặt khối trống.
Ông T

3
@ Mr.T NULL và nil giống hệt nhau về giá trị. Cả hai đều được xác định là 0 và không bao giờ có khả năng thay đổi. Vì vậy, an toàn khi sử dụng NULL ở bất cứ đâu bạn muốn hoặc có thể sử dụng nil.
ashevin

1
@ Mr.T Quan điểm của tôi là việc sử dụng cái này sẽ không bao giờ gây ra sự cố bởi vì ở cấp mã được biên dịch, chúng giống hệt nhau và vì lý do thực tế, sẽ luôn như vậy. Nói chung, việc loại bỏ các cảnh báo của trình biên dịch là một ý tưởng tốt, nhưng nói với mọi người rằng đó là lỗi sử dụng NULL thay vì nil đơn giản là sai.
ashevin


6

Vâng, những gì bạn nói là hoàn toàn chính xác và đó là cách để làm điều đó. Tôi đã viết phương pháp này và luôn sử dụng nó để làm mờ dần trong hình ảnh của tôi. Tôi đối phó với CALayerđiều này. Bạn cần nhập Core Animation cho việc này.

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

Bạn có thể làm ngược lại cho Fade ra một hình ảnh. Sau khi nó biến mất. Bạn chỉ cần loại bỏ nó khỏi giám sát (đó là UIImageView). [imageView removeFromSuperview].


Tôi thêm mã này sau khi đặt hình ảnh vào UIImageView, dường như có một chớp mắt khi bắt đầu hoạt hình.
Autobots

4

Bạn cũng có thể đóng gói tính năng mờ dần trong một lớp con, để sau đó bạn có thể sử dụng nó như một UIImageView thông thường, như trong ví dụ sau:

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

Một triển khai có thể sau đây.

Lưu ý: cách bạn thực sự thực hiện setImage:chức năng mờ dần trong chức năng có thể thay đổi và có thể là một trong những ví dụ tuyệt vời khác được mô tả trong các câu trả lời khác cho câu hỏi này - tạo ra một cách nhanh chóng UIImageViewnhư tôi đang làm ở đây là một chi phí không thể chấp nhận được trong tình huống cụ thể của bạn .

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

Đoạn mã trên dựa trên một vài giả định (bao gồm cả ARC được kích hoạt trong dự án XCode của bạn), chỉ nhằm mục đích làm bằng chứng về khái niệm, và vì lợi ích của sự rõ ràng và tập trung, nó vẫn có liên quan bằng cách bỏ qua mã không liên quan quan trọng. Xin đừng chỉ sao chép-dán nó một cách mù quáng.


3

Tôi cần sự chuyển đổi để lặp lại vô thời hạn. Phải mất rất nhiều thử nghiệm và lỗi cho cái này nhưng cuối cùng tôi đã nhận được kết quả cuối cùng mà tôi đang tìm kiếm. Đây là những đoạn mã để thêm hình ảnh động vào UIImageView trong UITableViewCell.

Đây là mã có liên quan:

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

Xin chào Tôi đã tự hỏi nếu bạn có thể thêm một số thông tin về [self setVarietyImageView: cell.imageView] của bạn; phương pháp như tôi có thể lấy ô cuối cùng để hoạt hình hoặc tất cả để hoạt hình nhưng thực sự nhanh, Cảm ơn
gav

Xin chào, "iversityImageView "là một tham chiếu yếu trong trình điều khiển khung nhìn để tôi có thể gán cho cell.imageView và tham chiếu nó sau trong phương thức 'animateImages'. @property (nonatomic, yếu) UIImageView * giốngImageView; Bạn có thể làm cho hình ảnh xoay nhanh hơn bằng cách đặt "thời lượng" ngắn hơn trong "quá trình chuyển đổi". Hy vọng đây là những gì bạn đang yêu cầu.
Christopher

Xin chào Christopher cảm ơn bạn đã trả lời, tôi đã tự hỏi về "setVarietyImageView:" Tôi giả sử một loại phương thức void nào đó cho phép sử dụng lại vì tôi chỉ có thể làm động các ô cuối cùng. Một lần nữa Cảm ơn bạn đã trả lời, tất cả các bài hát hay nhất của Gav
gav

Phương pháp này được tạo bằng cách sử dụng khai báo "thuộc tính" tiêu chuẩn. Ví dụ: @property (nonatomic, yếu) UIImageView * giốngImageView. Đây là một tham chiếu "yếu" vì nó đề cập đến một biến cục bộ khác (imageView của ô bảng). Thay vào đó, tôi có thể đã tham chiếu đến ô của bảng và truy cập vào cell.imageView trong phương thức animateImages. Tôi hi vọng cái này giúp được.
Christopher

2

Sau khi chơi xung quanh UIView.transition()và gặp sự cố với .transitionCrossDissolvetùy chọn (Tôi đã cố gắng làm động các hình ảnh thay đổi bên trong một UIImageView và quá trình chuyển đổi xảy ra ngay lập tức mà không có hoạt hình) Tôi phát hiện ra rằng bạn chỉ cần thêm một tùy chọn cho phép bạn tạo các thuộc tính thay đổi bên trong chế độ xem ( Swift 4.2 ):

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

Ngoài ra: nếu bạn có bất kỳ cuộc phỏng vấn nào trên imageView của mình, nó cũng sẽ được vẽ lại và nó có thể ngăn hoạt ảnh. Ví dụ, tôi đã có chế độ xem phụ với độ mờ trên imageView của mình và trong trường hợp đó hoạt hình không hoạt động. Vì vậy, tôi chỉ thay đổi hệ thống phân cấp chế độ xem của mình và di chuyển mờ sang chế độ xem của chính nó và đặt nó trên imageView.


0

Đây là cách tôi làm ngắn nhất. Tạo một hình ảnh động UIView và cam kết nó trên imageView của bạn.

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

0

Bằng cách sử dụng highlightedImagetài sản này có thể được thực hiện đơn giản hơn một chút. Đây là một ví dụ trong Swift 3. Đầu tiên, đặt cả hình ảnh bình thường và hình ảnh được tô sáng:

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

Và khi bạn muốn thay đổi giữa những hoạt hình đó:

UIView.transition(with: imageView, duration: 0.3, options: .transitionCrossDissolve, animations: { self.imageView.isHighlighted = !self.imageView.isHighlighted}, completion: .none)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.