Animare il cambiamento di una vista

Questa tecnica è utilizzabile sia per creare dissolvenze in uno slideshow di UIImage che per animare la variazione di UI in una UIView.

1
2
3
4
5
6
7
8
/* qui il codice che modifica la vista */
 
CATransition *transition = [CATransition animation];
transition.duration = 1.0f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;
 
[aView.layer addAnimation:transition forKey:nil];
/* qui il codice che modifica la vista */

CATransition *transition = [CATransition animation];
transition.duration = 1.0f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;

[aView.layer addAnimation:transition forKey:nil];

Si può aggiungere un .subtype, ad esempio se si vuole far scorrere la vista e decidere la direzione:

1
2
3
4
5
CATransition *transition = [CATransition animation];
transition.duration = .2f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromLeft;
CATransition *transition = [CATransition animation];
transition.duration = .2f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromLeft;

(fonte)

Rotazioni e ancoraggi per animazioni e gesti

Quando si anima un oggetto dell’interfaccia in iOS si possono eseguire una serie molto ampia di movimenti, cambi di colore, dimensioni e quant’altro. Quando parliamo però di rotazioni talvolta può essere utile ridefinire il punto attorno al quale l’oggetto deve eseguire la rotazione.

Infatti, anche se non ci si pensa spesso, una rotazione senza ridefinire altro che l’angolo, avviene attorno al centro dell’oggetto, ma molte rotazioni non sono corrette se avvengono in questa maniera (pensiamo ad una gamba che calcia un pallone, una mazza da golf che colpisce una pallina o la testa di un personaggio che fa cenno di “no”).

Iniziamo con una rotazione eseguita con Quartz:

1
2
3
4
5
6
7
8
9
10
<code>#import <QuartzCore/QuartzCore.h>
 
CABasicAnimation *fullRotation;
fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
fullRotation.fromValue = [NSNumber numberWithFloat:0];
fullRotation.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
fullRotation.duration = 3.5f;
fullRotation.repeatCount = MAXFLOAT;
 
[view.layer addAnimation:fullRotation forKey:@"360"];   </code>
<code>#import <QuartzCore/QuartzCore.h>

CABasicAnimation *fullRotation;
fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
fullRotation.fromValue = [NSNumber numberWithFloat:0];
fullRotation.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
fullRotation.duration = 3.5f;
fullRotation.repeatCount = MAXFLOAT;

[view.layer addAnimation:fullRotation forKey:@"360"];   </code>

Mentre, se vogliamo cambiare il punto di ancoraggio dobbiamo cambiare l’anchorPoint e il position del layer (proprietà su cui agisce CoreGraphics:)

1
2
3
4
self.imgView.layer.anchorPoint = CGPointMake(0.0,1.0);
self.imgView.layer.position = CGPointMake(100,200.0);
CGAffineTransform cgaRotateHr = CGAffineTransformMakeRotation(-(3.141/4));
[self.imgView setTransform:cgaRotateHr];
self.imgView.layer.anchorPoint = CGPointMake(0.0,1.0);
self.imgView.layer.position = CGPointMake(100,200.0);
CGAffineTransform cgaRotateHr = CGAffineTransformMakeRotation(-(3.141/4));
[self.imgView setTransform:cgaRotateHr];

Per una chiara spiegazione dei riferimenti che determinano il punto di ancoraggio delle rotazioni, vedere questo articolo.

Riguardo i gesti invece, è spesso necessario eseguire manipolazioni multiple di oggetti.

Innanzitutto un buon esempio per le gesture che possono determinare le manipolazioni comunemente conosciuto come scale, move e rotate si può trovare a questa pagina, mentre qui trovate una spiegazione di come effettuare il reset di rotazione e scala.

Infine un piccolo suggerimento su come eseguire contemporaneamente più trasformazioni su un oggetto:

1
2
3
4
5
6
// Rotate 45 degrees
CGAffineTransform rotate = CGAffineTransformMakeRotation(45*(M_PI/180));
// Move to the left
CGAffineTransform translate = CGAffineTransformMakeTranslation(-50,0);
// Apply them to a view
self.view.transform = CGAffineTransformConcat(translate, rotate);
// Rotate 45 degrees
CGAffineTransform rotate = CGAffineTransformMakeRotation(45*(M_PI/180));
// Move to the left
CGAffineTransform translate = CGAffineTransformMakeTranslation(-50,0);
// Apply them to a view
self.view.transform = CGAffineTransformConcat(translate, rotate);

 

Animare le UIImageView: activityIndicator e indicatore lampeggiante

Se l’UIActivityIndicator di fabbrica (nelle sue tre forme possibili) non ci dovesse piacere, oppure voglia che una immagini lampeggi, per richiamare l’attenzione, possiamo crearcene di personalizzati sfruttando la classe UIImageView.

UIImageView, infatti, non è soltanto un contenitore di immagini, ma permette di mostrare facilmente una animazione semplicemente specificando quali immagini vanno usate, che durata deve avere l’animazione, e facendo partire l’animazione stessa.

Andreas di BlackWhale.at illustra un esempio molto semplice, una volta creati 8 file png con un indicatore di attività personalizzato ogni volta ruotato di 45°:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//Create the first status image and the indicator view
UIImage *statusImage = [UIImage imageNamed:@"status1.png"];
UIImageView *activityImageView = [[UIImageView alloc] 
                initWithImage:statusImage];
 
//Add more images which will be used for the animation
activityImageView.animationImages = [NSArray arrayWithObjects:
            [UIImage imageNamed:@"status1.png"],
            [UIImage imageNamed:@"status2.png"],
            [UIImage imageNamed:@"status3.png"],
            [UIImage imageNamed:@"status4.png"],
            [UIImage imageNamed:@"status5.png"],
            [UIImage imageNamed:@"status6.png"],
            [UIImage imageNamed:@"status7.png"],
            [UIImage imageNamed:@"status8.png"],
            nil];
 
//Set the duration of the animation (play with it
//until it looks nice for you)
activityImageView.animationDuration = 0.8;
 
//Position the activity image view somewhere in 
//the middle of your current view
activityImageView.frame = CGRectMake(
            self.view.frame.size.width/2
                -statusImage.size.width/2, 
            self.view.frame.size.height/2
                -statusImage.size.height/2, 
            statusImage.size.width, 
            statusImage.size.height);
 
//Start the animation
[activityImageView startAnimating];
 
//Add your custom activity indicator to your current view
[self.view addSubview:activityImageView];
//Create the first status image and the indicator view
UIImage *statusImage = [UIImage imageNamed:@"status1.png"];
UIImageView *activityImageView = [[UIImageView alloc] 
				initWithImage:statusImage];

//Add more images which will be used for the animation
activityImageView.animationImages = [NSArray arrayWithObjects:
			[UIImage imageNamed:@"status1.png"],
			[UIImage imageNamed:@"status2.png"],
			[UIImage imageNamed:@"status3.png"],
			[UIImage imageNamed:@"status4.png"],
			[UIImage imageNamed:@"status5.png"],
			[UIImage imageNamed:@"status6.png"],
			[UIImage imageNamed:@"status7.png"],
			[UIImage imageNamed:@"status8.png"],
			nil];

//Set the duration of the animation (play with it
//until it looks nice for you)
activityImageView.animationDuration = 0.8;

//Position the activity image view somewhere in 
//the middle of your current view
activityImageView.frame = CGRectMake(
			self.view.frame.size.width/2
				-statusImage.size.width/2, 
			self.view.frame.size.height/2
				-statusImage.size.height/2, 
			statusImage.size.width, 
			statusImage.size.height);

//Start the animation
[activityImageView startAnimating];

//Add your custom activity indicator to your current view
[self.view addSubview:activityImageView];

Per semplificare un passaggio possiamo tener conto che, come moltissimi elementi grafici, anche UIImageView è posizionabile tramite la proprietà center che permette di definire il CGPoint del centro del frame, anziché l’intero frame.

Se invece volessimo far lampeggiare un indicatore (come una stellina o un led, giusto per fare un esempio), sarò sufficiente usare due png, uno con l’oggetto spento e uno con l’oggetto acceso, per farli alternare.

Infine, se l’immagine deve interrompere la propria animazione in un punto qualsiasi del codice, come ad esempio alla fine del caricamento di una tabella, sarà sufficiente creare una proprietà UIImageView (e sintetizzarla nel file di implementazione), anziché dichiararla in un solo metodo. Per chiarimenti su quest’ultimo punto, chiedete pure nei commenti.

Semplici animazioni nelle UIView

Per animare uno o più oggetti in una UIView è sufficiente seguire questo schema di massima:

1
2
3
4
5
6
7
8
9
10
// proprietà di partenza
 
[UIView beginAnimations:@"NomeAnimazione" context:nil];
[UIView setAnimationDuration:4.5];
[UIView setAnimationDelay:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
 
// proprietà di arrivo
 
[UIView commitAnimations];
// proprietà di partenza

[UIView beginAnimations:@"NomeAnimazione" context:nil];
[UIView setAnimationDuration:4.5];
[UIView setAnimationDelay:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];

// proprietà di arrivo

[UIView commitAnimations];

Ad esempio potremmo far spostare un oggetto cambiando il valore oggetto.frame.origin.x all’interno del blocco Animations, ma possiamo anche far apparire o scomparire degli oggetti regolandone la proprietà alpha.

Nell’esempio l’animazione dura 4.5 secondi, parte con un ritardo di 1 secondo, e segue una delle quattro curve d’animazione disponibili che ne regola la velocità lungo il percorso.