Зникають / розчиняються при зміні образу 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.