UIImageView의 이미지를 변경할 때 페이드 / 디졸브


160

두 개를 만드는 대신 하나의보기 UIImageViews를 변경하는 것이 논리적으로 보입니다 image. 그렇게하면 인스턴트 스위치 대신 두 이미지 사이에 페이드 / 크로스 디졸브가 발생합니까?


1
@ kumar-kl 수정 사항이 중요한 태그를 제거했습니다. 그렇게하지 마십시오.
Eric Aya

1
@KumarKL 그러나 여기서 "objective-c"는 우선 순위가 낮은 태그 가 아닙니다 ! 그냥 "빠른"을 추가하기 위해 그것을 제거하지 마십시오, 이것은 말이되지 않습니다, 그것은 실제로 경계 기물 파손입니다 ...
Eric Aya

1
@EricD, Ok 나는 같은 반복을하지 않습니다. 여러분의 관심에 감사드립니다.
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

@ OutMan 당신은 user577888에 의해 아래의 새로운 방법을 사용하는 것이 좋습니다.
Mirkules 2016 년

또한 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 자체를 대상으로 지정 하여이 작업을 수행했습니다.
Desmond

7
@ user577888 단지 작은 것입니다. 빈 완성 블록에 nil을 전달해야합니다. 블록은 함수 포인터가 아니며 (^로 표시) objective-c 객체처럼 작동합니다. NULL을 전달하면 컴파일러는이를 0 또는 (void *) 0으로 해석합니다. 어떤 이유로 transitionWithView : ...의 기본 코드가 유효성을 검사하지 않고 실수로 완료 블록 (예 : [완료 사본])에 메시지를 보내는 경우 오류가 발생합니다. 따라서 블록을 비워 두려면 항상 objective-c의 nil을 사용해야합니다.
Mr. T

3
@ Mr.T NULL과 nil의 값은 동일합니다. 둘 다 0으로 정의되며 변경 될 가능성이 없습니다. 따라서 nil을 사용하거나 사용할 수있는 곳이면 NULL을 사용하는 것이 안전합니다.
ashevin

1
@ Mr.T 내 요점은 컴파일 된 코드 수준에서 동일하고 실제적인 이유로 항상 같기 때문에 하나를 사용하면 충돌이 발생하지 않는다는 것입니다. 일반적으로 컴파일러 경고를 억제하는 것이 좋지만 사람들에게 nil 대신 NULL을 사용하는 것은 오류라고 말하는 것이 잘못입니다.
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

안녕하세요 Gav, "varietyImageView"는 뷰 컨트롤러에서 약한 참조이므로 cell.imageView에 할당하고 나중에 'animateImages'메서드에서 참조 할 수 있습니다. @property (비 원자, 약점) UIImageView * varietyImageView; "transitionWithView"에서 더 짧은 "지속 시간"을 설정하여 이미지를 더 빠르게 회전시킬 수 있습니다. 희망적으로 이것은 당신이 요구하는 것입니다.
Christopher

안녕하세요 Christopher는 답장을 보내 주셔서 감사합니다. "setVarietyImageView :"에 대해 궁금해했습니다. 마지막 셀에만 애니메이션을 적용 할 수 있었기 때문에 재사용이 가능한 일종의 void 메소드가 있다고 가정합니다. 답장 해 주셔서 감사합니다. 모든 최고의 Gav
gav

이 방법은 표준 "속성"선언을 사용하여 생성됩니다. 예를 들어, @property (비 원자, 약한) UIImageView * varietyImageView입니다. 다른 지역 변수 (테이블 셀의 imageView)를 참조하기 때문에 "약한"참조입니다. 대신 테이블 셀에 대한 참조를 만들고 animateImages 메소드의 cell.imageView에 액세스 할 수 있습니다. 이게 도움이 되길 바란다.
Christopher

2

장난하고 옵션으로 UIView.transition()문제가 발생한 후 .transitionCrossDissolve(하나의 UIImageView 내에서 변경되는 이미지에 애니메이션을 적용하려고 시도했지만 애니메이션없이 즉시 전환이 발생했습니다) 뷰 내에서 속성 변경을 애니메이션으로 만들 수있는 옵션을 하나 더 추가해야한다는 것을 알았습니다 ( 스위프트 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.