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


160

与其创建两个视图UIImageViews,不如简单地更改image一个视图的视图,这是合乎逻辑的。如果这样做,在两个图像之间是否有淡入淡出/交叉消失而不是立即切换?


1
@ kumar-kl您的编辑删除了一个重要标签。请不要那样做。
埃里克·艾雅

1
@KumarKL但是这里的“ objective-c” 并不是一个低优先级的标签!不要仅仅添加“ swift”就将其删除,这没有任何意义,这实际上是边界破坏行为……
Eric Aya

1
@EricD,好的,我不会重复相同的内容。感谢你的关心。
Kumar KL

Answers:


45

编辑:下面的@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的View Transitions示例项目:https : //developer.apple.com/library/content/samplecode/ViewTransitions/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007411


1
完善!我将此代码的一部分添加到SDWebImage的UIImageView(WebCache)类别中。
Autobots

@OutMan,最好使用user577888下面的更新方法。
Mirkules 2013年

我也以这种方式在SDWebImages回调之后设置图像,但是由于某种原因,如果我所有的单元都更新了,则在我的CollectionViewCell中,第一个单元格的图像最初是最后一个可见单元格的图像。我想这是某种方式来缓存presentationLayer或什么?有什么想法吗?
乔治2014年

支持编辑“下面的@algal有更好的解决方案”。
罗布

581

使用新的基于块的UIKit animation方法可以更加简单。

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

    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)

斯威夫特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
其他答案是正确的,但已过时(和/或过于冗长)。
史蒂文·克莱默

3
不必在超级视图上进行过渡。通过将UIImageView本身指定为目标,我设法完成了这项工作。
Desmond

7
@ user577888只是一件小事。您应该将nil传递给空的完成块。块不是函数指针(用^表示),其操作类似于Objective-C对象。如果传递NULL,则编译器会将其解释为0或(void *)0。如果由于某种原因transitionWithView:...的基础代码在不检查其有效性的情况下意外地将消息发送到完成块(例如[completion copy]),则将导致错误。因此,在将块设置为空时,应始终使用Objective-C的nil。
T先生

3
@ Mr.T NULL和nil的值相同。两者都定义为0,并且都不可能更改。因此,在您可能或可能使用nil的任何地方使用NULL是安全的。
阿什温

1
@ Mr.T我的观点是,一个使用另一个将永远不会导致崩溃,因为在编译的代码级别上,它们是相同的,并且出于实际原因,总是如此。通常,禁止编译器警告是一个好主意,但是告诉人们使用NULL而不是nil是错误的,这是完全错误的。
ashevin


6

是的,您说的是绝对正确的,那就是做到这一点的方法。我编写了此方法,并始终使用它淡化我的图像。我CALayer为此处理。您需要为此导入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;
}

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


在将图像设置到UIImageView之后,我添加了此代码,开始动画时似乎眨眼了。
Autobots

4

您还可以将淡入功能包装在子类中,以便随后将其用作公共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),仅用作概念证明,并且出于清晰和重点的考虑,通过省略重要的不相关代码来保持相关性。请不要盲目地复制粘贴。


3

我需要过渡才能无限期地重复。为此花费了很多的尝试和错误,但是我终于得到了想要的最终结果。这些是用于将图像动画添加到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;
}

嗨,我想知道是否可以在[self setVarietyImageView:cell.imageView]上添加更多信息。方法,因为我可以让最后一个单元进行动画处理,也可以全部进行动画处理,但速度非常快,谢谢
gav 2013年

嗨,Gav,“ varietyImageView”在视图控制器中是一个弱引用,因此我可以将其分配给cell.imageView并稍后在方法“ animateImages”中对其进行引用。@property(非原子的,弱的)UIImageView * varietyImageView; 通过在“ transitionWithView”中设置较短的“持续时间”,可以使图像旋转更快。希望这是您要问的。
克里斯托弗·

嗨,克里斯托弗(Christopher),谢谢您的答复,我想知道“ setVarietyImageView”:我认为它的某种void方法可以重用,因为我只能为最后一个单元设置动画。再次感谢您的回复,祝一切
顺利

使用标准的“属性”声明生成此方法。例如,@ property(非原子,弱)UIImageView * varietyImageView。这是一个“弱”引用,因为它引用了另一个局部变量(表单元格的imageView)。相反,我本可以对表单元格进行引用,并在animateImages方法中访问cell.imageView。我希望这有帮助。
克里斯托弗·

2

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上。


0

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

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

0

通过使用该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 our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.