Исчезать / растворяться при изменении изображения UIImageView

160

Вместо создания двух UIImageViews, кажется логичным просто изменить imageодно представление. Если я это сделаю, есть ли в любом случае распад / перекрёстное растворение между двумя изображениями, а не мгновенное переключение?

Джош Кахане
источник
1
@ kumar-kl В вашем редакторе удален важный тег. Пожалуйста, не делай этого.
Эрик Ая
1
@KumarKL Но здесь «target-c» не является тегом с низким приоритетом! Не удаляйте его просто, чтобы добавить «быстрый», это не имеет смысла, это на самом деле пограничный вандализм ...
Эрик Ая
1
@EricD, хорошо, я не буду повторять то же самое. Спасибо за вашу заботу.
Кумар К.Л.

Ответы:

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;

См. Пример проекта View Transitions от Apple: https://developer.apple.com/library/content/samplecode/ViewTransitions/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007411

Mirkules
источник
1
Отлично! Я добавляю часть этого кода в категорию UIImageView (WebCache) SDWebImage.
Автоботы
@OutMan вам может быть лучше, используя новый метод ниже user577888.
Миркулес
Я также устанавливаю свое изображение после обратного вызова SDWebImages таким образом, но по какой-то причине в моем CollectionViewCell изображение первой ячейки изначально является изображением из последней видимой ячейки, если обновляются все мои ячейки. Я предполагаю, что это что-то вроде кэширования презентации, слоя или чего-то такого?!? Есть идеи что это может быть?
Георг
Upvote для редактирования "есть лучшее решение из @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 в качестве цели.
Десмонд
7
@ user577888 просто мелочь. Вы должны передать ноль в пустой блок завершения. Блоки не являются указателями на функции (как обозначено символом ^) и работают как объект target-c. Если вы передадите NULL, компилятор интерпретирует это как 0 или (void *) 0. Если по какой-то причине базовый код для transitionWithView: ... случайно отправляет сообщение в блок завершения (например, [копия завершения]) без проверки его достоверности, это приведет к ошибке. Таким образом, вы всегда должны использовать target-c's nil при установке блока как пустого.
Мистер Т
3
@ Mr.T NULL и nil идентичны по значению. Оба определены в 0, и ни один из них никогда не изменится. Таким образом, можно использовать NULL везде, где вы хотите или могли бы использовать nil.
Ашевин
1
@ Mr.T Моя точка зрения заключается в том, что использование одного над другим никогда не приведет к сбою, потому что на уровне скомпилированного кода они идентичны и по практическим причинам всегда будут. Подавление предупреждений компилятора, в общем, хорошая идея, но говорить людям, что использовать NULL вместо nil - ошибка, просто неправильно.
Ашевин
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;
}

Вы можете сделать наоборот для Fade out изображения. После того, как это исчезает. Вы просто удаляете его из суперпредставления (что есть UIImageView). [imageView removeFromSuperview],

Срикар Аппалараджу
источник
Я добавляю этот код после установки изображения в UIImageView, похоже, при запуске анимации мигает.
Автоботы
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];
        }];
    }
}

Приведенный выше код основан на нескольких допущениях (включая включение ARC в вашем проекте XCode), он предназначен только для подтверждения концепции, и в интересах ясности и направленности остается актуальным, опуская важный не связанный код. Пожалуйста, не копируйте это вслепую.

магма
источник
3

Мне нужно, чтобы переход повторялся до бесконечности. Для этого потребовалось много проб и ошибок, но я, наконец, получил конечный результат, который искал. Это фрагменты кода для добавления анимации изображения в UIImageView в UITableViewCell.

Вот соответствующий код:

@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]; метод, как я могу получить последнюю ячейку, чтобы оживить или все, чтобы оживить, но очень быстро, Спасибо
Гав
Привет, Гав, "ietyImageView "является слабой ссылкой в ​​контроллере представления, так что я могу назначить cell.imageView и ссылаться на него позже в методе 'animateImages'. @property (неатомный, слабый) UIImageView *ietyImageView; Вы можете заставить изображения вращаться быстрее, установив более короткую «продолжительность» в «transitionWithView». Надеюсь, это то, что вы спрашиваете.
Кристофер
Привет, Кристофер, спасибо за ответ, мне было интересно узнать о setVarietyImageView: я предполагаю, что это какой-то метод void, который допускает повторное использование, так как я смог анимировать только последнюю ячейку. Еще раз спасибо за ответ, всего наилучшего Гав
Гав
Этот метод генерируется с использованием стандартного объявления свойства. Например, @property (неатомный, слабый) UIImageView *ietyImageView. Это «слабая» ссылка, так как она ссылается на другую локальную переменную (imageView ячейки таблицы). Я мог бы вместо этого сделать ссылку на ячейку таблицы и получить доступ к cell.imageView в методе animateImages. Надеюсь, это поможет.
Кристофер
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, и в этом случае анимация не работает. Поэтому я просто изменил свою иерархию представлений и переместил размытие в его собственное представление и поместил его поверх imageView.

Павел
источник
0

Это я думаю самый короткий способ сделать это. Создайте анимацию UIView и передайте ее в свой imageView.

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[myImageView setAlpha:0.0];
[UIView commitAnimations];
divyenduz
источник
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)
Йенс Шварцер
источник