Cree una animación de plegado de página en 3D dibujo de página y efecto de plegado de lomo

Esta miniserie de dos partes le enseñará cómo crear un impresionante efecto de plegado de página con Core Animation. En esta entrega, primero aprenderá cómo crear una vista de cuaderno de bocetos y luego cómo aplicar una animación de plegado de columna básica en esa vista. Sigue leyendo!


Proyecto final de demostración


Descripción general del tutorial

Trabajando con el Vista La clase es fundamental para el desarrollo de SDK de iOS. Las vistas tienen tanto un aspecto visual (es decir, lo que se ve en la pantalla) como, por lo general, un aspecto de control (interacción del usuario mediante toques y gestos). El aspecto visual es manejado por una clase que pertenece al Core Animation Framework, llamado CALayer (que a su vez se implementa a través de OpenGL, solo que no nos importa bajar a ese nivel de abstracción aquí). Los objetos de capa son instancias de la CALayer clase o una de sus subclases. Sin profundizar demasiado en la teoría (¡esto es, después de todo, se supone que es un tutorial práctico!), Debemos tener en cuenta los siguientes puntos:

  • Cada vista en iOS está respaldada por una capa, que es responsable de su contenido visual. Programáticamente, a esto se accede como la propiedad de capa en la vista.
  • Hay una jerarquía de capas paralelas correspondiente a la jerarquía de vistas en la pantalla. Esto significa que si (digamos) una etiqueta es una subvista a un botón, entonces la capa de la etiqueta es la subcapa de la capa del botón. Estrictamente hablando, este paralelismo se mantiene siempre y cuando no agreguemos nuestras propias subcapas a la mezcla.
  • Varias propiedades que establecemos en las vistas (en particular, las vistas relacionadas con la apariencia) son en realidad propiedades en la capa subyacente. Sin embargo, la capa expone algunas propiedades que no están disponibles en el nivel de vista. En ese sentido, las capas son más poderosas que las vistas..
  • En comparación con las vistas, las capas son objetos más "ligeros". Por lo tanto, si para algún aspecto de nuestra aplicación requerimos visualización sin interactividad, entonces las capas son probablemente la opción más eficaz..
  • UNA CALayerEl contenido de 's consiste en un mapa de bits. Si bien la clase base es bastante útil como es, también tiene varias subclases importantes en Core Animation. En particular, hay CAShapeLayer Lo que nos permite representar formas mediante vectores..

Entonces, ¿qué podemos lograr con capas que no podemos hacer fácilmente con vistas directamente? 3D, por ejemplo, que es en lo que nos centraremos aquí.. CALayerLas capacidades de los usuarios ponen a su alcance efectos 3D y animaciones bastante sofisticados, sin tener que descender al nivel de OpenGL. Este es el objetivo detrás de este tutorial: demostrar un efecto 3D interesante que ofrece una pequeña muestra de lo que podemos lograr con CALayers.


Nuestro objetivo

Tenemos una aplicación de dibujo que le permite a un usuario dibujar en la pantalla con su dedo (para lo cual reutilizaré el código de un tutorial anterior mío). Si el usuario realiza un gesto de pellizco en el lienzo de dibujo, se dobla a lo largo de una línea vertical que se extiende a lo largo del centro del lienzo (como la columna vertebral de un libro). El libro doblado incluso proyecta una sombra en el fondo..

La parte de dibujo de la aplicación que estoy tomando prestada no es realmente importante aquí, y podríamos usar cualquier imagen para demostrar el efecto de plegado. Sin embargo, el efecto lo convierte en una metáfora visual muy agradable en el contexto de una aplicación de dibujo donde la acción de pellizco expone un libro con varias hojas (que contienen nuestros dibujos anteriores) que podemos explorar. Esta metáfora se ve notablemente en la aplicación Paper. Si bien para los propósitos del tutorial, nuestra implementación será más sencilla y menos sofisticada, pero no está demasiado lejos ... y, por supuesto, puede tomar lo que aprendió en este tutorial y hacerlo aún mejor.!


Geometría de capas en breve

Recuerde que en el sistema de coordenadas de iOS el origen se encuentra en la esquina superior izquierda de la pantalla, con el eje x aumentando hacia la derecha y el eje y hacia abajo. El marco de una vista describe su rectángulo en su sistema de coordenadas de supervisión. Las capas también pueden ser consultadas por su marco, pero hay otra forma (preferida) de describir la ubicación y el tamaño de una capa. Los motivaremos con un ejemplo simple: imagine dos capas, A y B, como pedazos de papel rectangulares. Le gustaría que la capa B sea una subcapa de A, así que arregla B encima de A con un alfiler, manteniendo los lados rectos en paralelo. El pin pasa a través de dos puntos, uno en A y uno en B. Saber la ubicación de estos dos puntos nos da una manera efectiva de describir la posición de B con respecto a A. Etiquetaremos el punto que el pin perfora en A el " Punto de anclaje "y el punto en posición B". Eche un vistazo a la siguiente figura, para la cual haremos los cálculos:

La figura parece que está pasando mucho, pero no se preocupe, la examinaremos poco a poco:

  • El gráfico superior muestra la relación jerárquica: la capa púrpura (A, de nuestra discusión anterior) se convierte en una subcapa de la capa azul (B). El círculo verde con el signo más es donde A se fija en B. El posición (en el sistema de coordenadas de A) se da como 32.5, 62.5.
  • Ahora dirija su atención al gráfico inferior. los punto de anclaje Se especifica de manera diferente. Sus relativo al tamaño de la capa B, de modo que la esquina superior izquierda en 0.0, 0.0 y la esquina inferior derecha en 1.0, 1.0. Dado que nuestro pin es un cuarto de la distancia a través del ancho de B y la mitad del camino hacia abajo, el punto de anclaje es 0.25, 0.5.
  • Sabiendo el tamaño de B (50 x 45) ahora podemos calcular la coordenada de la esquina superior izquierda. En relación con la esquina superior izquierda de B, el punto de anclaje es 0.25 x 50 = 12.5 puntos en la dirección x y 0.50 x 45 = 22.5 punto en la dirección y. Reste estos de las coordenadas de la posición y obtendrá las coordenadas del origen de B en el sistema de A: 32.5 - 12.5, 62.5 - 22.5 = 20, 40. Claramente, el marco de B es 20, 40, 50, 45.

El cálculo es bastante sencillo, así que asegúrese de que lo comprende bien. Le dará una buena idea de la relación entre la posición, el punto de anclaje y el marco..

El punto de anclaje es bastante significativo porque cuando realizamos transformaciones 3D en la capa, estas transformaciones se realizan con respecto al punto de anclaje. Hablaremos de eso a continuación (y luego verás un código, ¡lo prometo!).


Transformaciones de capa

Estoy seguro de que está familiarizado con el concepto de transformaciones, como escalado, traslación y rotación. En la aplicación Fotos en iOS 6, si pellizcas con dos dedos para acercar o alejar una foto de tu álbum, estás realizando una transformación de escala. Si haces un movimiento de giro con tus dos dedos, la foto gira, y si la arrastras manteniendo los lados paralelos, eso es traducción. Animación básica y CALayer triunfo Vista permitiéndole realizar transformaciones en 3D en lugar de solo 2D. Por supuesto, en 2013 nuestras pantallas iDevice aún son 2D, por lo que las transformaciones 3D emplean algunos trucos geométricos para engañar a nuestros ojos para que interpreten una imagen plana como un objeto 3D (el proceso no es diferente al de representar un objeto 3D en un dibujo de líneas hecho con un lápiz, en serio). Para lidiar con la tercera dimensión, necesitamos usar un eje z que imaginemos perforando la pantalla de nuestro dispositivo y perpendicular a ella.

El punto de anclaje es importante porque el resultado preciso de la misma transformación aplicada generalmente diferirá dependiendo de él. Esto es especialmente importante, y se entiende más fácilmente, con una transformación de rotación a través del mismo ángulo aplicado con respecto a dos puntos de anclaje diferentes en el rectángulo en la figura de abajo (el punto rojo y el punto azul). Tenga en cuenta que la rotación se encuentra en el plano de la imagen (o alrededor del eje z, si prefiere pensar de esa manera).


La animación de la página doble

Entonces, ¿cómo implementamos el efecto de plegado que buscamos? Mientras que las capas son realmente geniales, ¡no puedes doblarlas en el medio! La solución es, como estoy seguro de que has descubierto, usar dos capas, una para cada página en cada lado del pliegue. Basándonos en lo que discutimos anteriormente, vamos a trabajar de antemano las propiedades geométricas de estas dos capas:

  • Hemos elegido un punto a lo largo de la "espina de plegado" para que sea nuestro punto de anclaje para nuestras dos capas, porque ahí es donde ocurre nuestro pliegue (es decir, la transformada de rotación). La rotación tiene lugar alrededor de una línea vertical (es decir, el eje y); asegúrese de visualizar esto. Podría decir que está bien, pero ¿por qué elegí el punto medio de la columna vertebral (en lugar de decir, un punto en la parte inferior o superior)? En realidad, en este caso particular, no hay una diferencia en lo que respecta a la rotación. Pero también queremos hacer una transformación a escala (haciendo las capas un poco más pequeñas a medida que se pliegan) y mantener el punto de anclaje en el medio significa que el libro se mantendrá bien centrado cuando se doble. Esto se debe a que, para la escala, el punto que coincide con el punto de anclaje permanece fijo en la posición.
  • El punto de anclaje para la primera capa es 1.0, 0.5 y para la segunda capa es 0.0, 0.5, en sus respectivos espacios coordinados. Asegúrate de confirmar eso de la figura antes de continuar!
  • El punto que se encuentra debajo del punto de anclaje en la super capa (es decir, la "posición") es el punto medio, por lo que sus coordenadas son ancho / 2, altura / 2. Recuerde que la propiedad de posición está en coordenadas estándar, no normalizada.
  • El tamaño de cada una de las capas es ancho / 2, altura.

Implementación

Ahora sabemos lo suficiente como para escribir un código!

Cree un nuevo proyecto de Xcode con la plantilla "Vaciar aplicación" y llámelo LayerFunTut. Conviértalo en una aplicación para iPad y habilite el conteo automático de referencias (ARC), pero deshabilite las opciones para datos básicos y pruebas unitarias. Guardalo.

En la página Destino> Resumen que aparece, desplácese hasta "Orientaciones de interfaz admitidas" y elija las dos orientaciones horizontales.

Desplácese hacia abajo hasta llegar a "Marcos y bibliotecas vinculadas", haga clic en "+" y agregue el marco central de QuartzCore, que se requiere para la animación central y los CALayers..

Comenzaremos por incorporar nuestra aplicación de dibujo en el proyecto. Crear una nueva clase de Objective-C llamada CanvasView, convirtiéndolo en una subclase de Vista. Pegue el siguiente código en CanvasView.h:

 // // CanvasView.h // #import  @interface CanvasView: UIView @property (nonatomic, strong) UIImage * incrementalImage; @fin

Y luego en CanvasView.m:

 // // CanvasView.m // #import "CanvasView.h" @implementation CanvasView UIBezierPath * ruta; Pts CGPoint [5]; uint ctr;  - (id) initWithCoder: (NSCoder *) aDecoder if (self = [super initWithCoder: aDecoder]) self.backgroundColor = [UIColor clearColor]; [self setMultipleTouchEnabled: NO]; ruta = [UIBezierPath bezierPath]; [ruta setLineWidth: 6.0];  devuélvete a ti mismo;  - (id) initWithFrame: (CGRect) frame self = [super initWithFrame: frame]; if (self) self.backgroundColor = [UIColor clearColor]; [self setMultipleTouchEnabled: NO]; ruta = [UIBezierPath bezierPath]; [ruta setLineWidth: 6.0];  devuélvete a ti mismo;  - (void) drawRect: (CGRect) rect [self.incrementalImage drawInRect: rect]; [[UIColor blueColor] setStroke]; [trazo de trayectoria];  - (void) touchesBegan: (NSSet *) toca withEvent: (UIEvent *) event ctr = 0; UITouch * touch = [toca cualquier objeto]; pts [0] = [toque locationInView: self];  - (void) touchesMoved: (NSSet *) toca conEvent: (UIEvent *) evento UITouch * touch = [toca cualquier Objeto]; CGPoint p = [toque locationInView: self]; ctr ++; pts [ctr] = p; if (ctr == 4) pts [3] = CGPointMake ((pts [2] .x + pts [4] .x) /2.0, (pts [2] .y + pts [4] .y) /2.0 ); [ruta moveToPoint: pts [0]]; [ruta addCurveToPoint: pts [3] controlPoint1: pts [1] controlPoint2: pts [2]]; [auto setNeedsDisplay]; pts [0] = pts [3]; pts [1] = pts [4]; ctr = 1;  - (void) touchesEnded: (NSSet *) toca withEvent: (UIEvent *) event [self drawBitmap]; [auto setNeedsDisplay]; [ruta removeAllPoints]; ctr = 0;  - (void) touchesCancelled: (NSSet *) toca withEvent: (UIEvent *) event [self touchesEnded: toca withEvent: event];  - (void) drawBitmap UIGraphicsBeginImageContextWithOptions (self.bounds.size, NO, 0.0); if (! self.incrementalImage) UIBezierPath * rectpath = [UIBezierPath bezierPathWithRect: self.bounds]; [[UIColor clearColor] setFill]; [rectpath fill];  [self.incrementalImage drawAtPoint: CGPointZero]; [[UIColor blueColor] setStroke]; [trazo de trayectoria]; self.incrementalImage = UIGraphicsGetImageFromCurrentImageContext (); UIGraphicsEndImageContext ();  @final

Como se mencionó anteriormente, este es solo el código de otro tutorial que escribí (con algunas modificaciones menores). Asegúrese de verificarlo si no está seguro de cómo funciona el código. Para los propósitos de este tutorial, sin embargo, lo importante es que CanvasView permite al usuario dibujar trazos suaves en la pantalla. Hemos declarado una propiedad llamada imagen incremental que almacena una versión de mapa de bits del dibujo del usuario. Esta es la imagen con la que estaremos "doblando". CALayers.

Es hora de escribir el código del controlador de vista e implementar las ideas que trabajamos anteriormente. Una cosa que no hemos discutido es cómo conseguimos la imagen dibujada en nuestro CALayer de modo que la mitad de la imagen se dibuja en la página izquierda y la otra mitad en la página derecha. Por suerte, solo son unas pocas líneas de código, de las que hablaré más adelante..

Crear una nueva clase de Objective-C llamada ViewController, hazlo una subclase de UIViewController, y no marque ninguna de las opciones que aparecen.

Pegue el siguiente código en ViewController.m

 // // ViewController.m // #import "ViewController.h" #import "CanvasView.h" #import "QuartzCore / QuartzCore.h" #define D2R (x) (x * (M_PI / 180.0)) // macro para convertir los grados a radianes @interface ViewController () @end @implementation ViewController CALayer * leftPage; CALayer * rightPage; UIView * curtainView;  - (void) loadView self.view = [[CanvasView alloc] initWithFrame: [[UIScreen mainScreen] applicationFrame]];  - (void) viewDidLoad [super viewDidLoad]; self.view.backgroundColor = [UIColor blackColor];  - (void) viewDidAppear: (BOOL) animated [super viewDidAppear: animated]; self.view.backgroundColor = [UIColor whiteColor]; CGSize size = self.view.bounds.size; leftPage = [capa CALayer]; rightPage = [capa CALayer]; leftPage.anchorPoint = (CGPoint) 1.0, 0.5; rightPage.anchorPoint = (CGPoint) 0.0, 0.5; leftPage.position = (CGPoint) size.width / 2.0, size.height / 2.0; rightPage.position = (CGPoint) size.width / 2.0, size.height / 2.0; leftPage.bounds = (CGRect) 0, 0, size.width / 2.0, size.height; rightPage.bounds = (CGRect) 0, 0, size.width / 2.0, size.height; leftPage.backgroundColor = [UIColor whiteColor] .CGColor; rightPage.backgroundColor = [UIColor whiteColor] .CGColor; leftPage.borderWidth = 2.0; // bordes agregados por ahora, para que podamos distinguir visualmente entre las páginas derecha e izquierda rightPage.borderWidth = 2.0; leftPage.borderColor = [UIColor darkGrayColor] .CGColor; rightPage.borderColor = [UIColor darkGrayColor] .CGColor; //leftPage.transform = makePerspectiveTransform (); // descomentar más tarde //rightPage.transform = makePerspectiveTransform (); // descomentar más tarde curtainView = [[UIView alloc] initWithFrame: self.view.bounds]; curtainView.backgroundColor = [UIColor scrollViewTexturedBackgroundColor]; [curtainView.layer addSublayer: leftPage]; [curtainView.layer addSublayer: rightPage]; UITapGestureRecognizer * foldTap = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector (fold :)]; [self.view addGestureRecognizer: foldTap]; UITapGestureRecognizer * unfoldTap = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector (desplegar :)]; unfoldTap.numberOfTouchesRequired = 2; [self.view addGestureRecognizer: unfoldTap];  - (anular) fold: (UITapGestureRecognizer *) gr // dibujando el mapa de bits "incrementalImage" en nuestras capas CGImageRef imgRef = ((CanvasView *) self.view) .incrementalImage.CGImage; leftPage.contents = (__bridge id) imgRef; rightPage.contents = (__bridge id) imgRef; leftPage.contentsRect = CGRectMake (0.0, 0.0, 0.5, 1.0); // este rectángulo representa la mitad izquierda de la imagen rightPage.contentsRect = CGRectMake (0.5, 0.0, 0.5, 1.0); // este rectángulo representa la mitad derecha de la imagen leftPage.transform = CATransform3DScale (leftPage.transform, 0.95, 0.95, 0.95); rightPage.transform = CATransform3DScale (rightPage.transform, 0.95, 0.95, 0.95); leftPage.transform = CATransform3DRotate (leftPage.transform, D2R (7.5), 0.0, 1.0, 0.0); rightPage.transform = CATransform3DRotate (rightPage.transform, D2R (-7.5), 0.0, 1.0, 0.0); [self.view addSubview: curtainView];  - (vacío) se despliega: (UITapGestureRecognizer *) gr leftPage.transform = CATransform3DIdentity; rightPage.transform = CATransform3DIdentity; // leftPage.transform = makePerspectiveTransform (); // descomentar más tarde // rightPage.transform = makePerspectiveTransform (); // descomentar más tarde [curtainView removeFromSuperview];  // UNCOMMENT TARDE: / * CATransform3D makePerspectiveTransform () CATransform3D transform = CATransform3DIdentity; transform.m34 = 1.0 / -2000; transformada de retorno  */ @final

Ignorando el código comentado por ahora, puede ver que la configuración de la capa es exactamente como la planeamos anteriormente..

Vamos a discutir este código brevemente:

  • Decidimos anular el -viewDidAppear: método en lugar de -viewDidLoad (a lo que podría estar más acostumbrado) porque cuando este último método se denomina, los límites de la vista aún están en modo vertical, pero nuestra aplicación se ejecuta en modo horizontal. Para el momento viewDidAppear: se llama, los límites se han establecido correctamente y, por lo tanto, colocamos nuestro código allí (hemos agregado temporalmente bordes gruesos para poder distinguir las capas izquierda y derecha a medida que aplicamos transformaciones en ellas).
  • Agregamos un reconocedor de gestos que registra un toque, y para cada toque hace que las páginas se vuelvan un poco más pequeñas (95% de su tamaño anterior) y las hace girar 7.5 grados. Los signos son diferentes porque una de las páginas gira en el sentido de las agujas del reloj mientras que la otra gira en sentido contrario a las agujas del reloj. Tendríamos que estudiar matemáticas para ver qué signo corresponde a qué dirección, pero como solo hay dos opciones, ¡es más fácil escribir el código y verificarlo! Por cierto, las funciones de transformación aceptan ángulos en radianes, así que usamos la macro D2R () convertir de radianes a grados. Una observación importante es que las funciones que toman una transformación en su argumento (como CATransform3DScale y CATransform3DRotate) "encadenar" una transformación con otra (el valor actual de la propiedad de transformación de capa). Otras funciones, como CATransform3DMakeRotation, CATransform3DMakeScale, CATransform3DIdentity acaba de construir la matriz de transformación adecuada. CATransform3DIdentity es la "transformación de identidad" que tiene una capa al crear una. Es análogo al número "1" en una multiplicación en el sentido de que la aplicación de una transformación de identidad a una capa deja su transformación sin cambios, al igual que multiplicar un número por uno.
  • Con respecto al dibujo, configuramos la propiedad de contenido de nuestras capas para que sea la imagen. Es muy importante tener en cuenta que configuramos el rectángulo de contenido (normalizado entre 0 y 1 a lo largo de cada dimensión) de modo que cada página solo muestre la mitad de la imagen correspondiente. Este sistema de coordenadas normalizado es el mismo que mencionamos anteriormente al hablar sobre el punto de anclaje, por lo que debería poder calcular los valores que usamos para cada mitad de la imagen..
  • los cortinavista el objeto simplemente actúa como un contenedor para las capas de la página (más precisamente, se hacen subcapas para la capa subyacente de curtainView). Recuerde que ya calculamos la ubicación y la geometría de las capas, y éstas son con respecto a la capa de curtainView. Al tocar una vez, se agrega esta vista en la parte superior de nuestra vista de lienzo y se aplica la transformación en la capa. Pulsar dos veces lo elimina, para revelar el lienzo una vez más, así como revertir la transformación de las capas a la transformación de identidad..
  • Tenga en cuenta el uso de Imagen cg aquí - y también CGColor antes - en lugar de UIImage y UIColor. Esto es porque CALayer opera en un nivel por debajo de UIKit, y funciona con tipos de datos "opacos" (en términos generales, no preguntes sobre su implementación subyacente) que se definen en el marco de Core Graphics. Clases objetivas-C como UIColor y UIImage pueden considerarse como envoltorios orientados a objetos en torno a sus versiones CG más primitivas. Para mayor comodidad, muchos objetos UIKit exponen su tipo de CG subyacente como una propiedad.

En el AppDelegate.m archivo, reemplace todo el código con lo siguiente (lo único que hemos agregado es incluir el archivo de encabezado ViewController y hacer un ViewController Instalar el controlador de vista raíz):

 // // AppDelegate.m // #import "AppDelegate.h" #import "ViewController.h" @implementation AppDelegate - (BOOL) application: (UIApplication *) application didFinishLaunchingWithOptions: (NSDictionary *) launchOptions self.window = \ [UIWindow alloc] initWithFrame: [[UIScreen mainScreen] lines]]; self.window.rootViewController = [[ViewController alloc] init]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; devuelve SÍ;  @final

Cree el proyecto y ejecútelo en el simulador o en su dispositivo. Garabatee un poco en el lienzo y luego toque la pantalla con un solo dedo para activar la acción de reconocimiento de gestos (al tocar con dos dedos, el efecto 3D finaliza y el lienzo de dibujo vuelve a aparecer).

No bastante ¡El efecto que estamos buscando! Que esta pasando?


Obteniendo nuestra perspectiva correcta

Primero, observe que las páginas se hacen más pequeñas con cada toque, por lo que el problema no reside en la transformación de escala, solo con la rotación. El problema es que aunque la rotación está ocurriendo en un espacio 3D (matemático), el resultado se proyecta en nuestras pantallas planas de la misma manera que un objeto 3D proyecta su sombra en una pared. Para transmitir profundidad, necesitamos usar algún tipo de señal. La señal más importante es la de la perspectiva: un objeto más cercano a nuestros ojos parece más grande que uno más lejano. Las sombras son otra gran señal, y llegaremos a ellas en breve. Entonces, ¿cómo incorporamos la perspectiva en nuestra transformación??

Hablemos un poco de transformaciones primero. ¿Qué son, en realidad? Hablando matemáticamente, deberías saber que si representamos los puntos de nuestra forma como vectores matemáticos, las transformaciones geométricas, como la escala, la rotación y la traducción, se representan como transformaciones matriciales. Lo que esto significa es que si tomamos una matriz que representa una transformación y la multiplicamos con un vector que representa un punto en nuestra forma, entonces el resultado de la multiplicación (también un vector) representa dónde termina ese punto después de transformarse. No podemos decir mucho más aquí sin sumergirnos en la teoría (de lo que realmente vale la pena aprender, si aún no lo conoces, ¡especialmente si pretendes incorporar efectos 3D geniales en tus aplicaciones!).

¿Qué pasa con el código? Anteriormente, establecemos la geometría de la capa estableciendo su punto de anclaje, posición, y límites. Lo que vemos en la pantalla es la geometría de la capa después de haber sido transformada por su transformar propiedad. Tenga en cuenta la función de llamadas que se ven como layer.transform = //… . Ahí es donde estamos configurando la transformación, que internamente es solo un estructura Representando una matriz 4 x 4 de valores de punto flotante. También tenga en cuenta que las funciones CATransform3DScale y CATransform3DRotate tomar la transformación actual de la capa como un parámetro. Eso es porque podemos componer varias transformaciones juntas (lo que significa que multiplicamos sus matrices juntas), con el resultado final como si hubieras realizado estas transformaciones una por una. Tenga en cuenta que solo estamos hablando del resultado final de la transformación, no de cómo la animación Core anima la capa.!

Volviendo al problema de la perspectiva, lo que necesitamos saber es que hay un valor en nuestra matriz de transformación que podemos modificar para obtener el efecto de perspectiva que buscamos. Ese valor es un miembro de la estructura de transformación, llamado m34 (los números indican su posición en la matriz). Para obtener el efecto que deseamos, debemos establecerlo en un número pequeño y negativo.

Descomentar las dos secciones comentadas en el ViewController.m archivo (el CATransform3D makePerspectiveTransform () función y las líneas leftPage.transform = makePerspectiveTransform (); rightPage.transform = makePerspectiveTransform (); y construir de nuevo. Esta vez el efecto 3D se ve más creíble.

También tenga en cuenta que cuando cambiamos la propiedad de transformación de un CALayer, El trato viene con una animación "gratuita". Esto es lo que queremos aquí, a diferencia de la capa que sufre su transformación de manera abrupta, pero a veces no lo es..

Por supuesto, la perspectiva solo llega tan lejos, cuando nuestro ejemplo se vuelve más sofisticado, ¡también usaremos sombras! También podríamos querer redondear las esquinas de nuestro "libro" y enmascarar nuestras capas de página con un CAShapeLayer puede ayudar con eso Además, nos gustaría usar un gesto de pellizco para controlar el plegado / desplegado para que se sienta más interactivo. Todo esto será cubierto en la segunda parte de este tutorial mini-series..

Lo invito a experimentar con el código, refiriéndose a la documentación de la API, e intente implementar el efecto deseado de manera independiente (¡incluso podría terminar haciéndolo mejor!).

Diviértete con el tutorial, y gracias por leer.!

Leer parte 2