Sto provando a implementare un'animazione a flip da utilizzare nel gioco da tavolo come l'applicazione per iPhone. L'animazione dovrebbe assomigliare ad un pezzo di gioco che ruota e cambia al colore della sua schiena (un po 'come un Reversi piece). Sono riuscito a creare un'animazione che capovolge il pezzo attorno al suo asse ortogonale, ma quando provo a capovolgerlo attorno ad un asse diagonale cambiando la rotazione attorno all'asse z anche l'immagine reale viene ruotata (non a caso). Invece vorrei ruotare l'immagine "così com'è" attorno ad un asse diagonale.Come ruoto un CALayer attorno a una linea diagonale?
Ho provato a cambiare layer.sublayerTransform
ma senza successo.
Ecco la mia attuale implementazione. Funziona facendo un trucco per risolvere il problema di ottenere un'immagine speculare alla fine dell'animazione. La soluzione è quella di non ruotare realmente il livello di 180 gradi, ma lo ruota di 90 gradi, cambia l'immagine e quindi la ruota indietro.
versione finale: Sulla base Lorenzos suggerimento per creare un'animazione keyed discreto e calcolare la matrice di trasformazione per ogni fotogramma. Questa versione tenta invece di stimare il numero di frame "guidanti" necessari in base alla dimensione del layer e quindi utilizza un'animazione con chiave lineare. Questa versione ruota con un angolo arbitrario in modo da ruotare attorno alla linea diagonale usando un angolo di 45 gradi.
Esempio di utilizzo:
[someclass flipLayer:layer image:image angle:M_PI/4]
Implementazione:
- (void)animationDidStop:(CAAnimationGroup *)animation
finished:(BOOL)finished {
CALayer *layer = [animation valueForKey:@"layer"];
if([[animation valueForKey:@"name"] isEqual:@"fadeAnimation"]) {
/* code for another animation */
} else if([[animation valueForKey:@"name"] isEqual:@"flipAnimation"]) {
layer.contents = [animation valueForKey:@"image"];
}
[layer removeAllAnimations];
}
- (void)flipLayer:(CALayer *)layer
image:(CGImageRef)image
angle:(float)angle {
const float duration = 0.5f;
CAKeyframeAnimation *rotate = [CAKeyframeAnimation
animationWithKeyPath:@"transform"];
NSMutableArray *values = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray *times = [[[NSMutableArray alloc] init] autorelease];
/* bigger layers need more "guiding" values */
int frames = MAX(layer.bounds.size.width, layer.bounds.size.height)/2;
int i;
for (i = 0; i < frames; i++) {
/* create a scale value going from 1.0 to 0.1 to 1.0 */
float scale = MAX(fabs((float)(frames-i*2)/(frames - 1)), 0.1);
CGAffineTransform t1, t2, t3;
t1 = CGAffineTransformMakeRotation(angle);
t2 = CGAffineTransformScale(t1, scale, 1.0f);
t3 = CGAffineTransformRotate(t2, -angle);
CATransform3D trans = CATransform3DMakeAffineTransform(t3);
[values addObject:[NSValue valueWithCATransform3D:trans]];
[times addObject:[NSNumber numberWithFloat:(float)i/(frames - 1)]];
}
rotate.values = values;
rotate.keyTimes = times;
rotate.duration = duration;
rotate.calculationMode = kCAAnimationLinear;
CAKeyframeAnimation *replace = [CAKeyframeAnimation
animationWithKeyPath:@"contents"];
replace.duration = duration/2;
replace.beginTime = duration/2;
replace.values = [NSArray arrayWithObjects:(id)image, nil];
replace.keyTimes = [NSArray arrayWithObjects:
[NSNumber numberWithDouble:0.0f], nil];
replace.calculationMode = kCAAnimationDiscrete;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = duration;
group.timingFunction = [CAMediaTimingFunction
functionWithName:kCAMediaTimingFunctionLinear];
group.animations = [NSArray arrayWithObjects:rotate, replace, nil];
group.delegate = self;
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
[group setValue:@"flipAnimation" forKey:@"name"];
[group setValue:layer forKey:@"layer"];
[group setValue:(id)image forKey:@"image"];
[layer addAnimation:group forKey:nil];
}
Codice originale:
+ (void)flipLayer:(CALayer *)layer
toImage:(CGImageRef)image
withAngle:(double)angle {
const float duration = 0.5f;
CAKeyframeAnimation *diag = [CAKeyframeAnimation
animationWithKeyPath:@"transform.rotation.z"];
diag.duration = duration;
diag.values = [NSArray arrayWithObjects:
[NSNumber numberWithDouble:angle],
[NSNumber numberWithDouble:0.0f],
nil];
diag.keyTimes = [NSArray arrayWithObjects:
[NSNumber numberWithDouble:0.0f],
[NSNumber numberWithDouble:1.0f],
nil];
diag.calculationMode = kCAAnimationDiscrete;
CAKeyframeAnimation *flip = [CAKeyframeAnimation
animationWithKeyPath:@"transform.rotation.y"];
flip.duration = duration;
flip.values = [NSArray arrayWithObjects:
[NSNumber numberWithDouble:0.0f],
[NSNumber numberWithDouble:M_PI/2],
[NSNumber numberWithDouble:0.0f],
nil];
flip.keyTimes = [NSArray arrayWithObjects:
[NSNumber numberWithDouble:0.0f],
[NSNumber numberWithDouble:0.5f],
[NSNumber numberWithDouble:1.0f],
nil];
flip.calculationMode = kCAAnimationLinear;
CAKeyframeAnimation *replace = [CAKeyframeAnimation
animationWithKeyPath:@"contents"];
replace.duration = duration/2;
replace.beginTime = duration/2;
replace.values = [NSArray arrayWithObjects:(id)image, nil];
replace.keyTimes = [NSArray arrayWithObjects:
[NSNumber numberWithDouble:0.0f], nil];
replace.calculationMode = kCAAnimationDiscrete;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.removedOnCompletion = NO;
group.duration = duration;
group.timingFunction = [CAMediaTimingFunction
functionWithName:kCAMediaTimingFunctionLinear];
group.animations = [NSArray arrayWithObjects:diag, flip, replace, nil];
group.fillMode = kCAFillModeForwards;
[layer addAnimation:group forKey:nil];
}
Che è un asse diagonale? – kennytm
Per asse diagonale intendo che la rotazione dovrebbe essere intorno alla diagonale del livello. Come se avessi afferrato due angoli diagonali dello strato e girandolo. –
Come, ruotare attorno alla retta 'y = x'? – kennytm