更改 UIImageView 的图像时淡入淡出/溶解

发布于 2024-12-08 11:58:31 字数 116 浏览 1 评论 0原文

简单地更改一个视图的 image 似乎是合乎逻辑的,而不是创建两个 UIImageViews。如果我这样做,是否会在两个图像之间进行淡入淡出/交叉溶解而不是即时切换?

Rather than creating two UIImageViews, it seems logical to simply change the image of one view. If I do that, is there anyway of having a fade/cross dissolve between the two images rather than an instant switch?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

烟雨扶苏 2024-12-15 11:58:31

使用新的基于块的 UIKit 动画 方法可以变得更加简单。

假设以下代码位于视图控制器中,并且您要交叉溶解的 UIImageView 是可通过属性 self.imageView 寻址的 self.view 的子视图,那么您所需要的就是:

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

完成。

要在 Swift 中执行此操作,就像这样:

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)

It can be much simpler using the new block-based, UIKit animation methods.

Suppose the following code is in the view controller, and the UIImageView you want to cross-dissolve is a subview of self.view addressable via the property self.imageView Then all you need is:

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

Done.

And to do it in Swift, it's like 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)
后eg是否自 2024-12-15 11:58:31

编辑:下面的@algal有一个更好的解决方案。

另一种方法是通过使用预定义的 CAAnimation 过渡:

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;

请参阅 Apple 的视图过渡示例项目:https://developer.apple.com/library/content/samplecode/ViewTransitions/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007411

Edit: there is a better solution from @algal below.

Another way to do this is by using predefined CAAnimation transitions:

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;

See the View Transitions example project from Apple: https://developer.apple.com/library/content/samplecode/ViewTransitions/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007411

青柠芒果 2024-12-15 11:58:31

对于 Swift 3.0.1:

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

参考:https://gist.github.com/licvido/bc22343cacfa3a8ccf88

For Swift 3.0.1 :

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

Reference: https://gist.github.com/licvido/bc22343cacfa3a8ccf88

只怪假的太真实 2024-12-15 11:58:31

是的,你说的是绝对正确的,这就是这样做的方法。我写了这个方法&总是用它来淡入我的图像。我为此处理CALayer。您需要为此导入核心动画。

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

您可以对淡出图像执行相反的操作。淡出之后。您只需将其从超级视图(即 UIImageView)中删除即可。 [imageView removeFromSuperview]

Yes what you say is absolutely correct and thats the way to do it. I wrote this method & always use this to Fade in my image. I deal with CALayer for this. You need to import Core Animation for this.

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

You could do the opposite for Fade out an image. After it fades out. You just remove it from superview (which is UIImageView). [imageView removeFromSuperview].

过度放纵 2024-12-15 11:58:31

您还可以将淡入功能封装在子类中,以便可以将其用作通用 UIImageView,如下例所示:

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

可能的实现如下。

注意:在 setImage: 函数中实际实现淡入的方式可以改变,并且可能是此问题的其他答案中描述的其他优秀示例之一 - 创建一个额外的正如我在这里所做的那样,在您的特定情况下,即时 UIImageView 可能是不可接受的开销

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

上述代码依赖于一些假设(包括在您的 XCode 项目中启用 ARC),仅作为证明为了清晰和重点,它通过省略重要的不相关代码来保持相关性。请不要盲目复制粘贴。

You could also package the fade-in feature in a subclass, so that you can then use it as a common UIImageView, as in the following example:

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

A possible implementation follows.

Note: the way you actually implement the fade-in in the setImage: function can change, and could be one of the other excellent examples described in the other answers to this question — creating an additional on-the-fly UIImageView as I'm doing here might be an unacceptable overhead in your specific situation.

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

The above code relies on a few assumptions (including ARC being enabled in your XCode project), is only intended as a proof of concept, and in the interest of clarity and focus, it stays relevant by omitting important unrelated code. Please don't just copy-paste it blindly.

自由如风 2024-12-15 11:58:31

我需要无限期地重复这种转变。为此我进行了很多尝试和错误,但我终于得到了我想要的最终结果。这些是用于将图像动画添加到 UITableViewCell 中的 UIImageView 的代码片段。

这是相关代码:

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

I needed the transition to repeat indefinitely. It took a LOT of trial and error for this one but I finally got the end-result I was looking for. These are code snippets for adding image animation to a UIImageView in a UITableViewCell.

Here is the relevant 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;
}
你怎么这么可爱啊 2024-12-15 11:58:31

在使用 UIView.transition() 并遇到 .transitionCrossDissolve 选项的问题(我试图在一个 UIImageView 内对图像进行动画处理,并且在没有动画的情况下立即发生转换),我发现发现您只需要添加一个选项,即可让您在视图内更改属性的动画(Swift 4.2):

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

此外:如果您的 imageView 上有任何子视图,它将是重绘也可能会阻止动画。例如,我的 imageView 上有模糊的子视图,在这种情况下动画不起作用。所以我只是改变了我的视图层次结构并将模糊移动到它自己的视图并将其放在 imageView 上。

After playing around with UIView.transition() and getting problems with .transitionCrossDissolve option (I was trying to animate images changing inside one UIImageView and transition occurred instantly without animation) I found out that you just need to add one more option which is letting you animate properties changing inside the view (Swift 4.2):

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

In addition: if your have any subviews on your imageView, it will be redrawn as well and it could prevent animation. For example, I had subview with blur on my imageView and in that case animation doesn't work. So I just changed my view hierarchy and move blur to its own view and put it over imageView.

你的笑 2024-12-15 11:58:31

我认为这是最短的方法。创建一个 UIView 动画并将其提交到您的 imageView 上。

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

This is I think the shortest way of doing it. Create a UIView animation and commit it on your imageView.

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[myImageView setAlpha:0.0];
[UIView commitAnimations];
秋心╮凉 2024-12-15 11:58:31

通过使用 highlightedImage 属性,这可以变得更简单一些。这是 Swift 3 中的一个示例。首先设置普通图像和突出显示图像:

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

当您想在这些动画之间进行更改时:

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

By using the highlightedImage property this can be made a bit more simple. Here's an example in Swift 3. First set both normal and highlighted image:

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

And when you want to change between those animated:

UIView.transition(with: imageView, duration: 0.3, options: .transitionCrossDissolve, animations: { self.imageView.isHighlighted = !self.imageView.isHighlighted}, completion: .none)
蹲墙角沉默 2024-12-15 11:58:31

如果您使用 SDWebImage,那么您很幸运。 SDWebImage 版本 4.3.0 及以上版本已内置 fade & fade(duration:) 方法。 文档

imageView.sd_imageTransition = .fade  //.fade(duration: 0.7)
let url = URL(string: "https://foo/bar.jpg")
imageView.sd_setImage(with: url)

If you're using SDWebImage, you're in luck. SDWebImage ver 4.3.0 onwards has inbuilt fade & fade(duration:) methods. DOC

imageView.sd_imageTransition = .fade  //.fade(duration: 0.7)
let url = URL(string: "https://foo/bar.jpg")
imageView.sd_setImage(with: url)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文