Зникають / розчиняються при зміні образу UIImageView


160

Замість того, щоб створити два UIImageViews, здається логічним просто змінити imageодин погляд. Якщо я це роблю, чи все-таки виникає розмикання / перехрестя між двома зображеннями, а не миттєвим перемикачем?


1
@ kumar-kl Вашою редакцією видалено важливий тег. Будь ласка, не робіть цього.
— Ерік Айя

1
@KumarKL Але тут "target-c" - це не тег низького пріоритету! Не видаляйте його просто для додавання "швидкого", це не має сенсу, це насправді прикордонний вандалізм ...
— Ерік Айя

1
@EricD, Добре, я не буду повторювати те саме. Дякую за вашу турботу.
— Кумар 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: https://developer.apple.com/library/content/samplecode/ViewTransitions/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007411


1
Ідеально! Я додаю частину цього коду до категорії UIImageView (WebCache) SDWebImage.
— Автоботи

@OutMan, можливо, вам буде краще використовувати новіший метод, описаний нижче користувачем577888.
— Міркулес

Я також встановлюю своє зображення після зворотного виклику SDWebImages таким чином, але чомусь у моєму CollectionViewCell є зображення першої комірки, спочатку тієї, яка є з останньої видимої комірки, якщо всі мої клітини оновлюються. Напевно, це якесь кешування презентаційного шару чи щось таке?!? Будь-які ідеї, що це може бути?
— Георг

Заявка на редагування "є краще рішення від @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]

Зроблено.

А робити це у Свіфті - це так:

    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 лише маленька річ. Вам слід передати нуль до порожнього блоку завершення. Блоки не функціонують покажчиками (як позначається ^) і діють як об’єкт-c об'єкта. Якщо ви передасте NULL, компілятор буде інтерпретувати це як 0 або (void *) 0. Якщо з якихось причин базовий код переходуWithView: ... випадково надсилає повідомлення до блоку завершення (наприклад, [копія завершення]) без перевірки його дійсності, це призведе до помилки. Тому ви завжди повинні використовувати нуль Objec-c, встановлюючи блок порожнім.
— Містер T

3
@ Mr.T NULL і nil однакові за значенням. Обидва визначаються як 0, і жоден з них не може змінитися. Таким чином, безпечно використовувати NULL в будь-якому місці, де ви могли б або могли використовувати нуль.
— Ашевін

1
@ Mr.T Моя думка полягає в тому, що використання одного над іншим ніколи не спричинить збій, оскільки на рівні складеного коду вони ідентичні, і з практичних причин завжди будуть. Замовчувати попередження компілятора - це гарна ідея, але говорити людям, що помилка використовувати NULL замість нуля - це просто неправильно.
— Ашевін


6

Так, те, що ви говорите, абсолютно правильне, і це спосіб зробити це. Я написав цей метод і завжди використовую це для Fade в своєму образі. Я 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, здається, при запуску анімації виникає миготіння.
— Автоботи

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]; метод, як я можу отримати останню клітинку для анімації або все для анімації, але дуже швидко, Дякую
— gav

Привіт Гав, "sortImageView" є слабкою посиланням у контролері подання, щоб я міг призначити cell.imageView і посилатися на нього пізніше в методі "animateImages". @ властивість (неатомічний, слабкий) UIImageView * sortImageView; Ви можете змусити зображення обертатися швидше, встановивши меншу "тривалість" у "переході з видом". Сподіваємось, про це ви запитуєте.
— Крістофер

Привіт Крістофер, дякую за відповідь, мені було цікаво про "setVarietyImageView:" Я припускаю, що це якийсь недійсний метод, який дозволяє повторно використовувати, оскільки мені вдалося анімувати останню клітинку. Ще раз Дякую за відповідь, все найкраще Gav
— gav

Цей метод генерується за допомогою стандартної декларації "властивості". Наприклад, @property (неатомічний, слабкий) UIImageView * sortImageView. Це "слабке" посилання, оскільки воно посилається на іншу локальну змінну (imageView комірки таблиці). Я міг би замість цього зробити посилання на комірку таблиці та отримати доступ до cell.imageView у методі animateImages. Я сподіваюся, що це допомагає.
— Крістофер

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.