2010-09-30 19 views
8

He estado tratando de desarrollar un objeto "CardView" basado en CALayer que tiene dos capas que se enfrentan entre sí para presentar las dos caras de una carta. He estado trabajando con cosas como la propiedad doublesided del CALayer y encuentro que los resultados son confusos. Mi clase base es CALayer y le agrego dos sublayers, una con una transformada M_PI/2 y ambas con doublesided = NO, pero tal como están las cosas, me sale la portada sin importar cómo gire la tarjeta y la parte posterior no muestra en absoluto. Si no creo el frente, la parte posterior se muestra por ambos lados y el texto está en una esquina, no en 48 puntos y borroso.Tratando de hacer una tarjeta de CALayers que puede voltear

Aquí hay un enlace a una captura de pantalla que muestra que la tarjeta acaba de terminar una revolución completa en una vista UIViewController's. Estás viendo la parte posterior del frente. Esto debe ser invisible, y la espalda debe estar mostrando ... creo ...

https://files.me.com/gazelips/lj2aqo


// CardView.h 

#import <Foundation/Foundation.h> 
#import <QuartzCore/QuartzCore.h> 

#define kCardWidth 100.0f 
#define kCardHeight 150.0f 

@interface CardView : CALayer { 
    CALayer *cardFront, *cardBack; 
} 

@property (nonatomic, retain) CALayer *cardFront, *cardBack; 

- (id)initWithPosition:(CGPoint)point; 
- (void)addPerspective; 
- (CALayer *)createFront; 
- (CALayer *)createBack; 

@end 

// CardView.m 

#import "CardView.h" 

@implementation CardView 

@synthesize cardFront, cardBack; 

static CATransform3D kPerspectiveTransform; 

- (id)initWithPosition:(CGPoint)point { 
    NSLog(@"--initWithPosition:CardView"); 
    self = [super init]; 
    if (self != nil) { 
     [self addPerspective]; 
     self.bounds = CGRectMake(0, 0, kCardWidth, kCardHeight); 
     self.position = point; 
     self.edgeAntialiasingMask = 0; 
     self.backgroundColor = [[UIColor clearColor] CGColor]; 
     self.borderColor = [[UIColor blackColor] CGColor]; 
     self.borderWidth = 0.5; 
     self.doubleSided = YES; 

     cardBack = [self createBack]; 
     [self addSublayer: cardBack]; 

     cardFront = [self createFront]; 
     [self addSublayer: cardFront]; 
    } 
    return self; 
} 

- (void)addPerspective { 
    NSLog(@"--prepare:CardView"); 
    kPerspectiveTransform = CATransform3DIdentity; 
    kPerspectiveTransform.m34 = -1.0/800.0; 
    self.transform = kPerspectiveTransform; 
} 

- (CALayer *)createFront { 
    NSLog(@"--createFront:CardView"); 
    CALayer *front = [[CALayer alloc] init]; 
    front.bounds = CGRectMake(0.0f, 0.0f, kCardWidth, kCardHeight); 
    front.position = CGPointMake(kCardWidth/2, kCardHeight/2); 
    front.edgeAntialiasingMask = 0; 
    front.backgroundColor = [[UIColor whiteColor] CGColor]; 
    front.cornerRadius = 8 * (kCardHeight/150); 
    front.borderWidth = 1; 
    front.borderColor = [[UIColor grayColor] CGColor]; 
    front.doubleSided = NO; 

    return [front autorelease]; 
} 

- (CALayer *)createBack { 
    NSLog(@"--createBack:CardView"); 
    CALayer *back = [[CALayer alloc] init]; 
    back.bounds = CGRectMake(0.0f, 0.0f, kCardWidth, kCardHeight); 
    back.position = CGPointMake(kCardWidth/2, kCardHeight/2); 
    back.backgroundColor = [[UIColor blueColor] CGColor]; 
    back.contentsGravity = kCAGravityResize; 
    back.masksToBounds = YES; 
    back.borderWidth = 4 * (kCardHeight/150); 
    back.borderColor = [[UIColor grayColor] CGColor];; 
    back.cornerRadius = 8 * (kCardHeight/150); 
    back.edgeAntialiasingMask = 0; 
    back.doubleSided = NO; 

    CATextLayer *textLayer = [CATextLayer layer]; 
    textLayer.font = [UIFont boldSystemFontOfSize:48]; 
    textLayer.bounds = CGRectMake(0.0f, 0.0f, kCardWidth, kCardHeight); 
    textLayer.position = CGPointMake(50.0f, 75.0f); 
    textLayer.string = @"Steve"; 
    [back addSublayer:textLayer]; 

    back.transform = CATransform3DMakeRotation(M_PI, 0.0f, 1.0f, 0.0f); 
    return [back autorelease]; 
} 

@end 

Respuesta

23

El truco terminó siendo el uso de CATransformLayer. Esta es una capa que es solo para contener otras capas (no puede tener cosas como backgroundColor o borderWidth). Sin embargo, mantiene la relación 3D real de sus capas secundarias (es decir, no las aplana como una normal CALayer). Así que puede hacer dos capas, invertir una y compensar su zPosition con un simple cabello y ponerlas en un CATransformLayer y ahora puede voltear esta capa principal seis veces desde el domingo y las capas secundarias permanecerán juntas y siempre se renderizarán correctamente. Bastante dulce y bajo sobrecarga!

+3

Si está buscando un buen tutorial sobre esto, esto realmente me ayudó: http://invasivecode.tumblr.com/post/29307073330/core-animation-transform-layer – Marc

+0

Tuve que votar esto no solo porque es el respuesta correcta, pero también para usar "seis formas del domingo" en él – ribeto

1

Hay una manera mucho más fácil haz esto, siempre y cuando solo intentes hacer un 'giro' normal.

Mire en el sistema de animación UIView, y hay una 'transitionWithView'. Puede aplicar una animación flip allí, y proporcionará el mismo efecto, casi sin trabajo.

+0

Gracias! Ya tengo una versión (creo que es la número 6) que usa una UIView y puedo darle la vuelta a los 3 ejes mientras la muevo. Acabo de hacer una UIView y agregué su capa a mi ViewController. Pero no pude entender la cosa de doble cara. – Steve

+0

Me encantaría ver la solución con la que finalmente fue. – Marvo

0

También leo muchas de las versiones para UIView. Después de unirlos todos juntos, esto es lo que obtuve y funciona.

Para configurar puse

1) la tarjeta bajo constructor de interfaces con un objeto vista que contiene un objeto UIImageView que muestra la parte delantera de la tarjeta. por lo que Ver-> Ver-> UIImageView-> archivo de imagen del frente de la tarjeta

2) Luego, el objeto View que contiene UIImageView se cambia a UIController Class (para que responda a los toques).

3) En el archivo de cabecera de la viewcontroller, he creado IBOutlet UIImageView cardView vinculada a la UIImageView y una flipCard IBAction vinculado al objeto View (que ahora es un objeto UIController) a través de evento "aterrizar”.

4) IBAction flipCard se implementa por la creación dinámica de otro subvista Ver objeto que contiene otro UIImageView, pero init la imagen parte trasera con.

5) usando CGRect, el marco y el centro del objeto de parte trasera están alineados con la parte delantera.

6) luego se invocan los métodos de animación de UIView para intercambiar las subvistas con animación.

Y eso hace el truco.

No estoy en mi mac ahora mismo, así que no tengo los códigos. Si alguien está interesado, puedo publicarlo más tarde.

+0

hola boobami, estoy interfiriendo en su código ... ¿puede publicarlo? gracias – sundsx

+0

Ha pasado un tiempo, pero déjame intentar encontrarlo. – boobami

Cuestiones relacionadas