Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Gráficos y multimedia
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Puntos a tratar
•
APIs para gráficos
•
Quartz 2D
•
Propiedades del contexto
•
Primitivas geométricas
•
Imágenes
•
Texto
•
Tipos de contexto
•
CoreAnimation
•
Propiedades de las capas
•
Animación de capas
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
APIs para gráficos
•
OpenGL ES
•
API multiplataforma
•
Gráficos 2D y 3D
•
Alto rendimiento (videojuegos)
•
APIs de Apple
•
Quartz 2D / CoreGraphics
•
CoreAnimation
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Quartz 2D / CoreGraphics
•
API de las plataformas de Apple para crear composiciones 2D
•
Por ejemplo gráficas
•
Todos sus elementos tienen el prefijo CG
•
No contiene objetos Objective-C, sino estructuras y funciones
•
Muchos objetos de UIKit pueden transformarse a CoreGraphics
CGColorRef color = [UIColor redColor].CGColor
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Contexto
•
Se dibuja en un contexto gráfico CGContextRef
•
Hace referencia a
•
Lienzo en el que se va a dibujar (por ejemplo la pantalla)
•
Atributos sobre la forma de dibujar en el lienzo (color, trazo, etc)
•
Podemos crear contextos para diferentes lienzos
•
Vista en pantalla
•
Imagen en memoria
•
Documento PDF
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Contexto de las vistas
•
Podemos obtener el contexto actualmente activo con:
•
Sobrescribir método drawRect: de las vistas
•
Dentro de él el contexto activo representa el área de la vista
•
Solicitar repintado de la vista cuando actualicemos gráficos
CGContextRef context = UIGraphicsGetCurrentContext();
-‐ (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
// Dibujar en el contexto
... }
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Sistema de coordenadas
•
Opuesto al sistema de UIKit en la coordenada y
•
Excepto cuando se crear en el contexto de una vista (UIView)
•
Podemos cambiar esto aplicando una transformación
CGContextTranslateCTM(context, 0.0, rect.size.height); CGContextScaleCTM(context, 1.0, -‐1.0);
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Puntos vs Pixels
•
El sistema de coordenadas de CoreGraphics está en puntos
•
Un iPhone siempre tiene 480 x 320 puntos
•
Un iPad siempre tiene 1024 x 768 puntos
•
Factor de escala
•
Indica la conversión entre puntos y pixels
•
Factor de escala de la pantalla
•
Es 1.0 en iPhone 3GS y anteriores y iPad 2 y anteriores
Resolución en puntos y en pixeles coinciden
•
Es 2.0 en dispositivos con pantalla retina (iPhone 4, ¿iPad 3?)
480 x 320 puntos equivalen a 960 x 640 pixels
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Atributos del pincel
•
Color de trazo y de relleno
•
Grosor del trazo
UIColor *colorRojo = [UIColor redColor]; UIColor *colorAzul = [UIColor blueColor];
CGContextSetStrokeColorWithColor(context, colorAzul.CGColor); CGContextSetFillColorWithColor(context, colorRojo.CGColor);
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Primitivas geométricas
•
Rectángulos
•
Trayectorias
CGRect rectangulo = CGRectMake(60, 40, 200, 400); CGContextStrokeRect(context, rectangulo); CGContextFillRect(context, rectangulo); CGContextMoveToPoint(context, 10, 10); CGContextAddLineToPoint(context, 20, 30); CGContextAddLineToPoint(context, 30, 35); CGContextStrokePath(context); (10,10) (20,30) (30,30)
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Imágenes
•
Podemos dibujarlas directamente con CoreGraphics
•
O utilizar la propia clase UIImage
•
Dibuja la imagen en el contexto actualmente activo
CGRect area = CGRectMake(0, 0, 320, 480);
CGImageRef imagen = [UIImage imageNamed: @"imagen.png"].CGImage;
CGContextDrawImage (contexto, area, imagen);
CGRect area = CGRectMake(0, 0, 320, 480);
UIImage *imagen = [UIImage imageNamed: @"imagen.png"];
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Texto
•
Establecer fuente y modo de dibujado
•
Dentro de una vista las coordenadas y están invertidas
•
El texto aparece al revés
•
Debemos corregir esto con
•
Dibujar una cadena con
CGContextSelectFont(context, "Helvetica-‐Bold", 12, kCGEncodingMacRoman); CGContextSetTextDrawingMode(context, kCGTextFill);
CGAffineTransform transform = CGAffineTransformMakeScale(1, -‐1); CGContextSetTextMatrix(context, transform);
NSString *cadena = @"Texto de prueba";
CGContextShowTextAtPoint(context, x, y,
[cadena cStringUsingEncoding: NSMacOSRomanStringEncoding], [cadena length]);
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Métricas del texto
•
En ocasiones necesitamos saber el tamaño en pixels de una
cadena de texto
•
Por ejemplo para dibujar un recuadro a su alrededor
•
Podemos saber dónde se ha terminado de dibujar el texto con:
•
Podemos también dibujar el texto en modo invisible
CGContextSetTextDrawingMode(context, kCGTextInvisible); CGContextShowTextAtPoint(context, 0, 0,
[cadena cStringUsingEncoding: NSMacOSRomanStringEncoding], [cadena length]);
CGPoint ancho = CGContextGetTextPosition(context); CGPoint position = CGContextGetTextPosition(context);
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Alternativas para dibujar texto
•
El método anterior sólo soporta codificación MacOS Roman
•
Problemas con el símbolo € por ejemplo
•
No ofrece apenas facilidades para alinear el texto
•
Es más sencillo dibujar texto directamente con UIString
•
El método
drawInRect:
pertenece a la categoría
UIStringDrawing
•
Para tener un mayor control podemos utilizar CoreText
NSString *cadena = @"Texto de prueba";
UIFont *font = [UIFont boldSystemFontOfSize: 12]; CGRect area = CGRectMake(10, 10, 100, 20);
[cadena drawInRect: area withFont:font
lineBreakMode:UILineBreakModeClip alignment:UITextAlignmentRight];
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Gradientes
•
La escala de colores del gradiente se mueve de 0 a 1
•
Podemos definir los colores en determinadas localizaciones
intermedias de dicho rango
•
El resto de colores se obtendrán por interpolación
size_t size = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 0.2, 0.2, 0.2, 1.0, // Color inicial (RGBA)
0.8, 0.8, 0.8, 1.0 }; // Color final (RGBA)
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(space, components, locations, size);
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Dibujado del gradiente
•
Debemos especificar el punto de inicial y final en la pantalla
•
Todo el contexto se llenará con el degradado especificado en la
dirección desde el punto origen al destino
•
El punto origen tendrá el color de la localización 0.0, y el destino
tendrá el de la localización 1.0
CGPoint startPoint = CGPointMake(0.0, 0.0); CGPoint endPoint = CGPointMake(0.0, 480.0);
CGContextDrawLinearGradient(context, gradient,
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Capas
•
Nos permiten crear una composición y repetirla en diferentes
lugares de la pantalla
•
La composición se guarda sólo una vez en la memoria de vídeo
•
Creamos un capa y obtenemos un contexto para dibujar en ella
•
Una vez dibujada la capa, volcamos al contexto principal
CGLayerRef layer = CGLayerCreateWithContext (context,
CGRectMake(0, 0, 50, 50), NULL); CGContextRef layerContext = CGLayerGetContext (layer);
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Contexto de imagen
•
Nos permite crear imágenes con CoreGraphics
•
Establecemos contexto de imagen con
•
Obtenemos contexto actual y dibujamos
•
Obtenemos la imagen resultante
UIGraphicsBeginImageContextWithOptions(CGSizeMake(320,240), NO, 1.0);
// Dibujar en el contexto
CGContextRef context = UIGraphicsGetCurrentContext(); ...
UIImage *imagen = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Contexto de PDF
•
Podemos generar un documento PDF con CoreGraphics
•
Abrimos contexto para generar un fichero PDF
•
Comenzamos página y obtenemos su contexto
•
Podemos repetir esto para cada página del documento
•
Cerramos el contexto, y el PDF se habrá generado
UIGraphicsBeginPDFContextToFile(@"fichero.pdf", CGRectZero, nil);
UIGraphicsBeginPDFPage();
// Dibujar en el contexto
CGContextRef context = UIGraphicsGetCurrentContext(); ...
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
CoreAnimation
•
Nos permite animar los elementos de la interfaz eficientemente
•
Su elemento principal es CALayer
•
No confundir con CGLayer
•
CGLayer sirve para crear una composición 2D, una vez creada las
capas no se pueden manipular de forma independiente
•
CALayer define elementos que componen la interfaz y que
podemos mover de forma independiente
•
Toda vista (UIView) contiene un CALayer
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Gráficos y multimedia © 2011-2012 Depto. Ciencia de la Computación e IA Gráficos y animación en iOS
Propiedades de las capas
•
Podemos decorarlas con distintos atributos
21
otras. Cuanto mayor sea la coordenada z, más cerca estará la capa del usuario, y tapará a
las capas con valores de z inferiores.
Es especialmente interesante en este caso la propiedad
transform, ya que nos permite
incluso aplicar transformaciones 3D a las capas. En el caso de las vistas, la propiedad
transform
tomaba un dato de tipo
CGAffineTransform, con el que se podía especificar
una transformación afín 2D (traslación, rotación, escalado o desencaje), mediante una
matriz de transformación 3x3. En el caso de las capas, la transformación es de tipo
CATransform3D
, que se especifica mediante una matriz de transformación 4x4 que nos
permite realizar transformaciones en 3D. Tendremos una serie de funciones para crear
distintas transformaciones de forma sencilla, como
CATransform3DMakeTranslation,
CATransform3DMakeRotation, y
CATransform3DMakeScale. También podemos aplicar
transformaciones sobre una transformación ya creada, pudiendo así combinarlas y crear
transformaciones complejas, con
CATransform3DTranslate,
CATransform3DRotate, y
CATransform3DScale.
Además de las propiedades anteriores, la capa ofrece una gran cantidad de propiedades
adicionales que nos van a permitir decorarla y tener un gran control sobre la forma en la
que aparece en pantalla. A continuación destacamos algunas de estas propiedades:
Propiedad Descripción
backgroundColor Color de fondo de la capa.
cornerRadius Podemos hacer que las esquinas aparezcan redondeadas con esta propiedad.
shadowOffset, shadowColor, shadowRadius, shadowOpacity
Permiten añadir una sombra a la capa, y controlar las propiedades de dicha sombra
borderWidth, borderColor Establecen el color y el grosor del borde de la capa.
doubleSided Las capas pueden animarse para que den la vuelta. Esta propiedad nos indica si al darle la vuelta la capa debe mostrarse también por la cara de atrás.
contents,
contentsGravity
Nos permite especificar el contenido de la capa como una imagen de tipo CGImageRef. Especificando la gravedad podemos indicar si queremos que la imagen se escale al tamaño de la capa, o que se mantenga su tamaño inicial y se alinee con alguno de los bordes.
Como hemos comentado anteriormente, las capas se organizan de forma jerárquica, al
igual que ocurría con las vistas. Podemos añadir una subcapa con el método
addLayer:CALayer *nuevaCapa = [CALayer layer;]
[self.view.layer addSublayer: nuevaCapa];
En la sección anterior vimos cómo dibujar en una vista utilizando Core Graphics. Si
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Posicionamiento de capas
•
En vistas (UIView) tenemos la propiedad
center
•
Posición del centro de las vistas
•
En capas (CALayer) tenemos propiedades
position y anchorPoint
•
anchorPoint indica el punto de la capa
que se utilizará como referencia para
posicionarla. Se mueve en coordenas
relativas a la capa (de 0 a 1). El anchor
point (0.5, 0.5) equivale al centro de la
capa, con este punto se comportaría como
las vistas.
•
position indica la posición en pantalla del
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Definir nuevas capas
•
Siempre deben estar contenidas en un UIView
•
Podemos agregar subcapas a la capa principal
•
Podemos dibujar en el contexto de dichas capas
•
Definir delegado para dibujar en la capa
•
Implementar método que dibuje en ella con CoreGraphics
CALayer *nuevaCapa = [CALayer layer;]
[self.view.layer addSublayer: nuevaCapa];
nuevaCapa.delegate = self;
-‐ (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context { // Codigo Core Graphics
... }
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Animación implícita de capas
•
Podemos animar una capa simplemente cambiando cualquiera
de sus propiedades
•
La propiedad cambiará gradualmente al nuevo valor
•
Esto sólo funciona con capas instanciadas por nosotros, no por
las que crea UIView
•
Para controlar las propiedades de la animación, o animar capas
de vistas, deberemos utilizar animación explícita
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Animación explícita de capas
•
Podemos definir animaciones básicas con CABasicAnimation
•
Indicamos la propiedad a animar como cadena KVC
•
Indicamos el valor inicial y final de la propiedad
•
Indicamos duración y otras propiedades de la animación
•
Añadimos la animación a la capa para reproducirla
CABasicAnimation *theAnimation=
[CABasicAnimation animationWithKeyPath:@"position.x"];
theAnimation.fromValue=[NSNumber numberWithFloat:100.0]; theAnimation.toValue=[NSNumber numberWithFloat:300.0];
theAnimation.duration=5.0; theAnimation.repeatCount=2; theAnimation.autoreverses=YES;
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Transiciones
•
Nos permite animar la entrada y salida de capas de la pantalla
•
Definimos una animación de transición
•
Aplicamos la animación sobre la capa padre
•
Al agregar o eliminar hijos de dicha capa padre, entrarán o
saldrán de pantalla con la animación especificada
CATransition *transition = [CATransition animation]; transition.duration = 0.5;
transition.type = kCATransitionMoveIn;
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Animación de vistas
•
Podemos animar directamente las vistas (UIView) sin tener que
bajar a CoreAnimation
•
Las animaciones se definen mediante bloques, donde
indicamos el valor final que queremos que tengas las
propiedades
•
Podemos modificar propiedades de distintas vistas
[UIView animateWithDuration:0.5 animations:^{
vista1.frame = CGRectMake(100,100,50,50); vista2.frame = CGRectMake(200,100,50,50); }];
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Transiciones de vistas
•
Nos permite reemplazar una vista por otra mediante una
animación
•
Debemos especificar la vista que entra y la vista que sale
•
vistaOrigen será eliminada de su supervista, y en su lugar se
añadirá vistaDestino
•
Podemos especificar diferente duración y tipos de animación
[UIView transitionFromView: vistaOrigen toView: vistaDestino duration: 0.5
options: UIViewAnimationOptionTransitionFlipFromLeft completion: nil];