UIImageViewの画像を変更するときにフェード/ディゾルブ


160

2つを作成するのではなく、1つのビューのUIImageViewsを単に変更するのimageが理にかなっています。その場合、インスタントスイッチではなく、2つの画像間でフェード/クロスディゾルブを行う方法はありますか?


1
@ kumar-kl編集により重要なタグが削除されました。しないでください。
Eric Aya

1
@KumarKLしかし、ここで「objective-c」は優先度の低いタグではありません。...これは意味をなさない、それは実際に境界線荒らしで、単に「SWIFT」を追加するためにそれを削除しないでください
エリック綾

1
@EricD、わかりました。同じことを繰り返すことはしません。ご心配をありがとう。
Kumar KL

回答:


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 2013年

@OutManの場合、user577888が以下の新しいメソッドを使用する方がよいでしょう。
ミルクルズ2013年

また、SDWebImagesコールバック後に画像を設定していますが、何らかの理由で私のCollectionViewCellの最初のセルの画像は、すべてのセルが更新された場合、最初は最後に表示されていたセルの画像です。私はそれがプレゼンテーションレイヤーをキャッシュするようなものだと思いますか?!?それが何であるかについてのアイデアはありますか?
Georg

編集に賛成票を投じてください。「以下の@algalからのより良い解決策があります。」
Rob

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
他の答えは正しいですが、時代遅れです(または過度に冗長です)。
Steven Kramer

3
スーパービューでトランジションを行う必要はありません。UIImageView自体をターゲットとして指定することで、これをうまく機能させることができました。
デズモンド2013年

7
@ user577888はほんの小さなことです。空の完了ブロックにnilを渡す必要があります。ブロックは(^で示される)関数ポインターではなく、objective-cオブジェクトのように動作します。NULLを渡すと、コンパイラはそれを0または(void *)0として解釈します。何らかの理由で、transitionWithView:...の基礎となるコードが、有効性をチェックせずに誤って完了ブロック(たとえば、[完了コピー])にメッセージを送信すると、エラーが発生します。したがって、ブロックを空に設定するときは、常にobjective-cのnilを使用する必要があります。
T氏

3
@ Mr.T NULLとnilの値は同じです。どちらも0に定義されており、どちらも変更される可能性はほとんどありません。したがって、nilを使用する、またはnilを使用できる場所ならどこでもNULLを使用しても安全です。
アシュビン

1
@ Mr.T私の要点は、コンパイルされたコードレベルでは同じであり、実際上の理由から常に同じであるため、どちらを使用してもクラッシュが発生しないということです。一般に、コンパイラの警告を抑制することは良い考えですが、nilの代わりにNULLを使用するのはエラーであることを人々に伝えるのは単に間違っています。
アシュビン2013年


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

画像をフェードアウトするには、逆の操作を行うことができます。フェードアウトした後。スーパービューから削除するだけです(つまりUIImageView)。[imageView removeFromSuperview]


UIImageViewに画像を設定した後、このコードを追加します。アニメーションを開始すると、瞬きがあるようです。
Autobots 2013年

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:関数に実際にフェードインを実装する方法は変わる可能性があり、この質問に対する他の回答で説明されている他の優れた例の1つである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

こんにちはGav、 "varietyImageView"はビューコントローラーの弱い参照なので、cell.imageViewに割り当てて、後でメソッド 'animateImages'で参照できます。@property(nonatomic、weak)UIImageView * varietyImageView; 「transitionWithView」で短い「期間」を設定することにより、画像をより速く回転させることができます。うまくいけば、これはあなたが求めているものです。
クリストファー

こんにちはクリストファー、返信ありがとうございます。 "setVarietyImageView:"について疑問に思っていました。私は、最後のセルをアニメーション化することしかできなかったため、再利用を可能にするなんらかのvoidメソッドを想定しています。再び返信ありがとうございます。最高のGav
gav

このメソッドは、標準の「プロパティ」宣言を使用して生成されます。たとえば、@ property(nonatomic、weak)UIImageView * varietyImageViewなどです。別のローカル変数(テーブルセルのimageView)を参照するため、これは「弱い」参照です。代わりに、テーブルセルを参照して、メソッドanimateImagesのcell.imageViewにアクセスすることもできます。これがお役に立てば幸いです。
クリストファー

2

オプションをいじっUIView.transition()て問題を解決した後.transitionCrossDissolve(私は1つのUIImageView内で変化するイメージをアニメーション化しようとしていて、アニメーションなしで即座に遷移が発生しました)ビュー内で変化するプロパティをアニメーション化できるオプションを1つ追加するだけでよいことがわかりました(Swift 4.2):

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

さらに、imageViewにサブビューがある場合、それも再描画され、アニメーションが妨げられる可能性があります。たとえば、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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.