2010-09-30 2 views
8

Ho cercato di sviluppare un oggetto "CardView" basato su CALayer che presenta due livelli rivolti l'uno verso l'altro per presentare i due lati di una scheda. Ho lavorato con cose come la proprietà doublesided dello CALayer e trovo i risultati confusi. La mia classe base è CALayer e sto aggiungendo due sublayers ad essa, uno con una trasformazione M_PI/2 ed entrambi con doublesided = NO ma così com'è, ottengo la parte anteriore che mostra non importa come ruoto la scheda e il retro non mostra affatto. Se non creo il fronte, la parte posteriore mostra entrambi i lati e il testo è in un angolo, non a 48 punti e sfocato.Tentativo di creare una scheda da CALayers che può capovolgere

Ecco un collegamento a uno screenshot che mostra la scheda che ha appena terminato un giro completo in una vista UIViewController's. Stai vedendo il retro del fronte. Questo dovrebbe essere invisibile, e la parte posteriore dovrebbe essere mostrando ... credo ...

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 

risposta

23

Il trucco è stato l'utilizzo di CATransformLayer. Questo è un livello che serve solo per contenere altri livelli (non può avere cose come backgroundColor o borderWidth). Tuttavia mantiene la vera relazione 3D dei suoi livelli figli (ad esempio, non li appiattisce come un normale CALayer). Quindi puoi creare due strati, lanciarne uno e sfalsare il suo zPosition solo un capello e metterli entrambi in un CATransformLayer e ora puoi capovolgere questo livello genitore sei volte da domenica e i livelli figlio rimangono bloccati insieme e sempre renderizzati correttamente. Abbastanza dolce e basso overhead!

+3

Se stai cercando un bel tutorial su questo, questo mi ha davvero aiutato: http://invasivecode.tumblr.com/post/29307073330/core-animation-transform-layer – Marc

+0

Ho dovuto sopravvalutare questo non solo perché è il risposta corretta ma anche per l'utilizzo di "sei modi da domenica" in esso – ribeto

1

C'è un modo molto più facile fallo, fintanto che stai solo provando a fare un normale "flip".

Cerca nel sistema di animazione UIView e c'è un 'transitionWithView'. È possibile applicare un'animazione di vibrazione lì, e fornirà lo stesso effetto, quasi senza lavoro.

+0

Grazie! Ho già ottenuto una versione (questo è il n. 6 credo) che utilizza un UIView e posso girarlo attorno a tutti e 3 gli assi mentre lo sto spostando. Ho appena creato un UIView e aggiunto il suo layer a ViewController. Ma non riuscivo a capire cosa fosse la doppia faccia. – Steve

+0

Mi piacerebbe vedere la soluzione alla quale sei arrivato alla fine. – Marvo

0

Ho letto anche molte versioni di UIView. Dopo averli messi insieme, questo è quello che ho ottenuto e funziona.

Per impostare I impostare

1) la scheda sotto costruttore di interfaccia con una sottofinestra che contiene un oggetto UIImageView che mostra la parte anteriore della carta. quindi View-> View-> UIImageView-> file immagine della parte anteriore della scheda

2) Quindi l'oggetto View contenente UIImageView viene modificato in Classe UIController (in modo che risponda ai tocchi).

3) Nel file di intestazione del viewcontroller, ho creato IBOutlet UIImageView CardView legata alla UIImageView e un IBAction Flipcard collegato all'oggetto View (che ora è un oggetto UIController) tramite evento "touch down”.

4) IBAction Flipcard è attuato creando dinamicamente un'altra sottomaschera Vista oggetto contenente un'altra UIImageView, ma init l'immagine retro con.

5) utilizzando CGRect, il telaio e centro dell'oggetto posteriore sono allineate con la parte anteriore.

6) quindi i metodi di animazione di UIView sono chiamati per scambiare le sottoview con l'animazione.

E questo è il trucco.

Non sono al mio mac adesso, quindi non ho i codici. Se qualcuno è interessato, posso postarlo più tardi.

+0

hi boobami, mi sto intromettendo nel tuo codice ... puoi pubblicarlo? grazie – sundsx

+0

È passato un po 'di tempo ma lasciami provare a trovarlo. – boobami