¿Cuándo necesito establecer la propiedad contentsScale de un CALayer?

En la documentation, Apple declara que debe considerar el factor de escala de una capa cuando:

  • Crea capas adicionales de Core Animation con diferentes factores de escala y las comstack en su propio contenido.
  • Establece la propiedad de contenido de una capa de Core Animation directamente

La última afirmación no está totalmente clara para mí. También dicen:

Las aplicaciones que utilizan capas de Core Animation directamente para proporcionar contenido pueden necesitar ajustar su código de dibujo para tener en count los factores de escala. Normalmente, cuando dibuja en drawRect: método de su vista, o en drawLayer: inContext: método del delegado de la capa, el sistema ajusta automáticamente el context de los charts para tener en count los factores de escala.

Normalmente o siempre? y esto es válido solo para la capa de respaldo hospedada de la vista o cada capa que agrego como subcapa a la capa de respaldo? porque también dicen:

Si su aplicación crea capas sin una vista asociada, el factor de escala de cada nuevo object de capa se establece inicialmente en 1.0. Si no cambia ese factor de escala, y si luego dibuja la capa en una pantalla de alta resolución, los contenidos de la capa se escalarán automáticamente para compensar la diferencia en los factores de escala. Si no desea que los contenidos sean escalados, puede cambiar el factor de escala de la capa a 2.0, pero si lo hace sin proporcionar contenido de alta resolución, su contenido existente puede parecer más pequeño de lo que esperaba. Para solucionar ese problema, debe proporcionar contenido de mayor resolución para su capa.

Tengo dificultades para imaginar una capa sin una vista, puedo imaginar una jerarquía de capas, pero tan pronto como quiero mostrarlas, debería agregarla como una subhierajía de la capa de respaldo de la vista, o si existen otros medios para usarlas (como crear y simplemente generar cambios en un context)?

El motor de composition de Core Animation examina la propiedad contentsScale de cada capa para determinar si los contenidos de esa capa deben escalarse durante la composition. Si su aplicación crea capas sin una vista asociada, el factor de escala de cada nuevo object de capa se establece inicialmente en 1.0. Si no cambia ese factor de escala, y si luego dibuja la capa en una pantalla de alta resolución, los contenidos de la capa se escalarán automáticamente para compensar la diferencia en los factores de escala. Si no desea que los contenidos sean escalados, puede cambiar el factor de escala de la capa a 2.0, pero si lo hace sin proporcionar contenido de alta resolución, su contenido existente puede parecer más pequeño de lo que esperaba. Para solucionar ese problema, debe proporcionar contenido de mayor resolución para su capa.

¿Qué significa eso en realidad? Cuando hago algo como esa layer.contents = (id)image.CGImage Necesito configurar el contentsScale.
¿También necesito configurarlo cuando mi capa dibuja sus contenidos llamando al método de delegado drawLayer:inContext: y la capa no es la capa de respaldo de una vista?

re: contenido de la capa a través de -drawRect: o -drawLayer: inContext:

Normalmente o siempre? y esto es válido solo para la capa de respaldo hospedada de la vista o cada capa que agrego como subcapa a la capa de respaldo?

Siempre. Cuando se invocan estos methods, el context actual ya tendrá el factor de escala aplicado. Por ejemplo, si su capa es de 10pt x 10pt, tiene un límite de {0,0,10,10}, independientemente de la escala de contenido. Si el contenido Scale = 2 (por ejemplo, estás en retina), esto es en realidad 20×20 píxeles. CALayer ya habrá configurado una tienda de respaldo 20x20px y aplicará un factor de escala CGContextScaleCTM (context, 2, 2).

Esto es para que pueda hacer su dibujo en su espacio conceptual 10×10 de cualquier manera, pero la tienda de respaldo se duplica si los píxeles se duplican.

Tengo dificultades para imaginar una capa sin una vista, puedo imaginar una jerarquía de capas, pero tan pronto como quiero mostrarlas, debería agregarla como una subhierajía de la capa de respaldo de la vista, o si existen otros medios para usarlas (como crear y simplemente generar cambios en un context)?

Puede crearlos, agregarlos como subcapas y establecer su delegado en un object donde implementa -drawLayer: inContext :, o puede establecer directamente los contenidos de la capa. En iOS, UIView es un envoltorio bastante superficial en torno a un CALayer, por lo que generalmente tiene sentido crear subvistas en lugar de crear directamente subcapas, por lo que no estás tan familiarizado con este uso. En OS X, un NSView respaldado por capas es un contenedor grande y complicado alnetworkingedor de un CALayer, por lo que tiene mucho más sentido hacer jerarquías enteras de capas dentro de una única vista.

¿Qué significa eso en realidad? Cuando hago algo como esa layer.contents = (id) image.CGImage Necesito configurar el contentsScale.

Sí. Pero lo que este pasaje de la documentation te dice es que si no quieres parecer feo, una capa de 10pt x 10pt con contenido Scale of 2, necesita contenidos que tengan una image de 20px x 20px. Es decir, debe prestar atención a la escala de contenido de la capa cuando está configurando directamente el contenido de la capa si desea evitar escalar los artefactos.

¿También necesito configurarlo cuando mi capa dibuja sus contenidos llamando al método de delegado drawLayer: inContext: y la capa no es la capa de respaldo de una vista?

Sí. Si está creando capas usted mismo (no creado a través de UIView), debe configurar manualmente su escala. Por lo general, esta es solo la escala layer.contentsScale = [[UIScreen mainScreen]]. (Nuevamente, en OS X esto es un poco más complicado ya que las pantallas pueden aparecer y desaparecer mientras se ejecutan).

Si bien una capa casi siempre se usa dentro de una vista, la capa puede haberse creado ad-hoc y agregarse como una subcapa de la capa de la vista, o asignarse como máscara de otra capa. En ambos casos, la propiedad contentsScale tendría que establecerse. Por ejemplo:

 UIView *myMaskedView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; CALayer *myMaskLayer = [CALayer new]; myMaskLayer.frame = myMaskedView.bounds; UIImage *maskImage = [UIImage imageNamed:@"some_image"]; myMaskLayer.contents = (id)maskImage.CGImage; myMaskLayer.contentsScale = maskImage.scale; myMaskedView.layer.mask = myMaskLayer; 

También es posible que desee crear una jerarquía de capas para realizar animaciones, sin usar cada capa para respaldar una vista:

 UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; CALayer *sublayerA = [CALayer new]; sublayerA.contentsScale = myView.layer.contentsScale; [myView.layer addSublayer:sublayerA]; CALayer *sublayerB = [CALayer new]; sublayerB.contentsScale = myView.layer.contentsScale; [myView.layer addSublayer:sublayerB]; // Continue adding layers 

Esto es especialmente importante para los dispositivos Retina, que tienen una escala de pantalla nativa de 2.0; una capa con la escala pnetworkingeterminada de 1.0 mostraría una notable pixelación.

En OS X, básicamente

  1. -backingScaleFactor el -backingScaleFactor de -backingScaleFactor tu window
  2. establece cada (!) capa -contentsScale a esa escalaFactor
  3. implementar -layer:shouldInheritContentsScale:fromWindow: en un controller
  4. establezca la capa de cada capa -delegate a ese controller

Sé que está mal visto aquí en SO para solo hacer reference a una URL externa, pero es difícil describir esto. Aquí hay un código que funciona correctamente para mí con respecto a los factores de escala:

https://github.com/JanX2/ScrollingAboutWindow

Espero que ayude.