En lugar de crear dos UIImageViews
, parece lógico simplemente cambiar el image
de 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 image
de 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 animation
mé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.imageView
Entonces 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 CALayer
esto. 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 UIImageView
como 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 .transitionCrossDissolve
opció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 highlightedImage
propiedad, 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)