2012-05-19 8 views
11

En iOS, podemos trazar una línea en drawRect usandoEn iOS, ¿por qué el dibujo de UIBezierPath no requiere un contexto?

CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextBeginPath (context); 
CGContextMoveToPoint(context, 0, 0); 
CGContextAddLineToPoint(context, 100, 100); 
CGContextStrokePath(context); 

pero también puede dibujar un rectángulo si quitamos el código anterior, y sólo tiene que utilizar:

preguntas
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 100, 100)]; 
[path stroke]; 

dos relacionadas:

1) ¿Por qué no necesita UIBezierPath obtener o usar el contexto actual?

2) ¿Qué pasa si tengo dos contextos: uno para la pantalla, y uno es un contexto de mapa de bits, entonces, ¿cómo saber qué contexto dibujar para UIBezierPath? Pensé que podría ser UIGraphicsSetCurrentContext pero no existe.

Respuesta

22

UIBezierPath utiliza un contexto. Utiliza el contexto gráfico de UIKit actual. Esto es exactamente lo mismo que ya está recibiendo con UIGraphicsGetCurrentContext().

Si desea UIBezierPath para utilizar un contexto diferente, puede usar UIGraphicsPushContext(), pero debe recordar usar UIGraphicsPopContext() cuando haya terminado.

+1

por lo que sería usar 'UIGraphicsPushContext (myBitmapContext);' para empezar a dibujar en un contexto de mapa de bits? –

+2

@ 動靜 能量: es correcto –

5

En iOS, podemos trazar una línea en drawRect usando

He destacado la parte importante de esta declaración. Dentro de drawRect:, UIKit ya ha configurado un contexto para usted, y cualquier instrucción de dibujo basada en objetos va directamente a ese contexto. UIBezierPath está usando ese contexto, simplemente no necesita ser pasado explícitamente.

En Cocoa Touch, siempre debe haber un contexto de dibujo (en este caso, el contexto finalmente se pintará en la pantalla). Si no estuvieras dentro de drawRect:, deberías crear un contexto tú mismo.

CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextBeginPath (context); 
CGContextMoveToPoint(context, 0, 0); 

en cuenta que la primera llamada a la función es ObtenerCurrentContext(). Cuando utilizas la interfaz de dibujo funcional de CoreGraphics, necesitas pasar un contexto a cada función, pero no estás creando una aquí, solo estás recuperando la que ya existe.

Graphics contexts están en una pila. Si desea dibujar en un contexto que ha creado, lo inserta en la pila usando UIGraphicsPushContext() (como Kevin ya mencionó), luego vuelve al anterior.

6

Pensé que podría ser útil mencionar que CGContextFillRect es ~ 8.5x más rápido que usar un UIBezierPath de lo que puedo decir (en caso de que el rendimiento sea un factor y suponiendo que no necesita usar un UIBezierPath para un dibujo más complejo)

He añadido un poco de tiempo al ejemplo de HazardMap de Apple (http://developer.apple.com/library/ios/#samplecode/HazardMap/Introduction/Intro.html) y el tiempo en ms por rect es de ~ 0.00064 ms/rect para el enfoque CGContextFillRect versus ~ 0.00543 ms/rect para el enfoque UIBezierPath, presumiblemente b/c este último requiere más sobrecarga de mensajes.

i.e.Estoy comparando usando

CGContextFillRect(ctx, boundaryCGRect); 

frente a la utilización

UIBezierPath* path = [UIBezierPath bezierPathWithRect:boundaryCGRect]; 
[path fill]; 

en el bucle interior en HazardMapView (además de los anteriormente mencionados cambios para empujar/POP el contexto que se pasa a HazardMapView drawMapRect: zoomScale: InContext :).

ETA

+1

Tenga en cuenta que los números anteriores son del simulador de iPhone 6.0 que se ejecuta en una Macbook Pro (principios de 2012). Ejecutar esto en un iPad3 real CGContextFillRect parece ser ~ 5.7x más rápido que usar el enfoque UIBezierPath. YMMV, por supuesto, dependiendo del dispositivo que esté utilizando (la configuración de optimización no parece afectar demasiado). – ETA

Cuestiones relacionadas