En lugar de crear dos UIImageViews, parece lógico simplemente cambiar el imagede una vista. Si hago eso, ¿hay alguna forma de disolver el fundido / cruce entre las dos imágenes en lugar de un cambio instantáneo?
En lugar de crear dos UIImageViews, parece lógico simplemente cambiar el imagede una vista. Si hago eso, ¿hay alguna forma de disolver el fundido / cruce entre las dos imágenes en lugar de un cambio instantáneo?
Respuestas:
Editar: hay una mejor solución de @algal a continuación .
Otra forma de hacerlo es mediante el uso de transiciones CAAnimation predefinidas:
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;
Consulte el proyecto de ejemplo Ver transiciones de Apple: https://developer.apple.com/library/content/samplecode/ViewTransitions/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007411
Puede ser mucho más simple usar los nuevos UIKit animationmétodos basados en bloques .
Suponga que el siguiente código está en el controlador de vista, y el UIImageView que desea disolver en forma cruzada es una subvista de self.view direccionable a través de la propiedad. self.imageViewEntonces todo lo que necesita es:
UIImage * toImage = [UIImage imageNamed:@"myname.png"];
[UIView transitionWithView:self.imageView
duration:5.0f
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
self.imageView.image = toImage;
} completion:nil]
Hecho.
Y para hacerlo en Swift, es así:
let toImage = UIImage(named:"myname.png")
UIView.transitionWithView(self.imageView,
duration:5,
options: UIViewAnimationOptions.TransitionCrossDissolve,
animations: { self.imageView.image = toImage },
completion: nil)
Swift 3, 4 y 5
let toImage = UIImage(named:"myname.png")
UIView.transition(with: self.imageView,
duration: 0.3,
options: .transitionCrossDissolve,
animations: {
self.imageView.image = toImage
},
completion: nil)
Para Swift 3.0.1:
UIView.transition(with: self.imageView,
duration:0.5,
options: .transitionCrossDissolve,
animations: { self.imageView.image = newImage },
completion: nil)
Referencia: https://gist.github.com/licvido/bc22343cacfa3a8ccf88
Sí, lo que dices es absolutamente correcto y esa es la forma de hacerlo. Escribí este método y siempre lo uso para desvanecerse en mi imagen. Trato con CALayeresto. Necesita importar Core Animation para esto.
+ (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;
}
Podrías hacer lo contrario para atenuar una imagen. Después de que se desvanece. Simplemente lo eliminas de la supervista (que es UIImageView). [imageView removeFromSuperview].
También puede empaquetar la función de fundido de entrada en una subclase, para que luego pueda usarla como un UIImageView común, como en el siguiente ejemplo:
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
Sigue una posible implementación.
Nota: la forma en que realmente implementa el fundido de entrada en la setImage:función puede cambiar, y podría ser uno de los otros excelentes ejemplos descritos en las otras respuestas a esta pregunta; crear un sobre la marcha adicional UIImageViewcomo lo estoy haciendo aquí podría Ser una sobrecarga inaceptable en su situación específica .
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];
}];
}
}
El código anterior se basa en algunas suposiciones (incluida la habilitación de ARC en su proyecto XCode), solo pretende ser una prueba de concepto, y en aras de la claridad y el enfoque, sigue siendo relevante omitiendo código importante no relacionado. Por favor, no solo copie y pegue a ciegas.
Necesitaba que la transición se repitiera indefinidamente. Tomó MUCHA prueba y error para este, pero finalmente obtuve el resultado final que estaba buscando. Estos son fragmentos de código para agregar animación de imágenes a un UIImageView en un UITableViewCell.
Aquí está el código relevante:
@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;
}
Después de jugar UIView.transition()y tener problemas con la .transitionCrossDissolveopción (estaba tratando de animar las imágenes que cambian dentro de un UIImageView y la transición se produjo instantáneamente sin animación) descubrí que solo necesita agregar una opción más que le permite animar las propiedades que cambian dentro de la vista ( Swift 4.2 ):
UIView.transition(with: self.imageView,
duration: 1,
options: [.allowAnimatedContent, .transitionCrossDissolve],
animations: { self.imageView.image = newImage },
completion: nil)
Además: si tiene subvistas en su imageView, también se volverá a dibujar y podría evitar la animación. Por ejemplo, tenía una subvista con desenfoque en mi imageView y en ese caso la animación no funciona. Así que simplemente cambié mi jerarquía de vistas y moví el desenfoque a su propia vista y lo puse sobre imageView.
Al usar la highlightedImagepropiedad, esto se puede hacer un poco más simple. Aquí hay un ejemplo en Swift 3. Primero configure la imagen normal y la resaltada:
let imageView = UIImageView(image: UIImage(named: "image"), highlightedImage: UIImage(named: "highlightedImage"))
Y cuando quieras cambiar entre esos animados:
UIView.transition(with: imageView, duration: 0.3, options: .transitionCrossDissolve, animations: { self.imageView.isHighlighted = !self.imageView.isHighlighted}, completion: .none)