2010-05-28 18 views
6

Un CAShapeLayer utiliza un CGPathRef para dibujar sus cosas. Así que tengo un camino de estrella, y quiero una sombra suave con un radio de alrededor de 15 unidades. Probablemente haya alguna funcionalidad agradable en algunas versiones nuevas de iPhone OS, pero necesito hacerlo yo mismo para una versión antigua de 3.0 (que la mayoría de la gente aún usa).Cómo dibujar sombras desplegables en iOS

Intenté hacer algunas cosas realmente desagradables: Creé un bucle forzado y se creó secuencialmente como 15 de esas rutas, transformándolas paso a paso para aumentar su tamaño. Luego, asignarlos a un nuevo CAShapeLayer creado y disminuir su alfa un poco en cada iteración. No solo que esta escala es matemáticamente incorrecta y es una mierda (¡debería ocurrir en relación con el contorno!), La sombra no es redondeada y se ve realmente fea. Es por eso que las bonitas sombras suaves tienen un radio.

Las puntas de una estrella no deben aparecer totalmente nítidas después de un tamaño de sombra de 15 unidades. Deben ser suaves como la crema. Pero en mi fea solución son tan simples como la estrella en sí misma, ya que lo único que hago es escalar la estrella 15 veces y disminuirla en alfa 15 veces. Feo.

Me pregunto cómo lo hacen los chicos grandes? Si tenía una ruta arbitraria, y esa ruta debe arrojar una sombra, ¿cómo funciona el algoritmo para hacerlo? Probablemente, la ruta tendría que expandirse 30 veces, punto por punto, en relación con la tangente del contorno, lejos de la parte rellena, y con solo 0,5 unidades para obtener una buena combinación.

Antes de reinventar la rueda, ¿alguien tiene un ejemplo útil o un enlace?

Respuesta

3

Una sombra es una máscara de escala de grises translúcida con la forma de un objeto borroso y desplazado.

CGContextSetShadowWithColor y CGContextSetShadow cómo esto se hace en el iPhone.Configura la sombra, luego dibuja algo y también se aplica una sombra.

Una CAShapeLayer no tiene una opción fácil para aplicar una sombra. Deberá crear una vista o capa personalizada y establecer la sombra antes de dibujar su forma.

no he probado, pero lo siguiente podría trabajar:

@interface ShadowShapeLayer : CAShapeLayer 
@end 

@implementation ShadowShapeLayer 
-(void) drawInContext:(CGContextRef)context { 
    CGContextSaveGState(context); 
    CGContextSetShadow(context , CGSizeMake(5 , 5) , 15); 
    [super drawInContext:context]; 
    CGContextRestoreGState(context); 
} 
@end 

Edit: Gracias Miser.

+0

Para CGContextSetShadow, el segundo parámetro debe ser un CGSize, como en CGSizeMake (5,5) –

1

Me hice la misma pregunta. No soy un experto en este tema en absoluto, pero tuve el siguiente pensamiento: Físicamente, un punto de un dibujo debería dar como resultado una sombra circular (o elíptica), semitransparente. Por lo tanto, un dibujo completo, que consiste en puntos múltiples, debería dar como resultado la combinación de muchas de tales sombras circulares.

Así que pinté una pequeña sombra en Photoshop (herramienta de pincel, tamaño 7, opacidad 33%, color # 3b3b3b). Es apenas visible:

alt text

Entonces escribí un pequeño HTML con Javascript sólo para tratar de ver lo que parece (definitivamente no es el ideal :-) técnica:

<!DOCTYPE html> 
<html> 
<head> 
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 
    <title>Title</title> 

    <script type="text/javascript" language="javascript"> 

     function pageload() { 
      var drawingContainerElem = document.getElementById("drawing-container"); 
      var shadowContainerElem = document.getElementById("shadow-container"); 

      this.drawDot = function(x, y) { 
       var imgElem = document.createElement("img"); 
       imgElem.style.left = x + "px"; 
       imgElem.style.top = y + "px"; 
       imgElem.src = "blue-dot.png"; 
       drawingContainerElem.appendChild(imgElem); 
      } 
      this.drawShadow = function(x, y) { 
       var imgElem = document.createElement("img"); 
       imgElem.style.left = x + "px"; 
       imgElem.style.top = y + "px"; 
       imgElem.src = "soft-shadow.png"; 
       shadowContainerElem.appendChild(imgElem); 
      } 
      this.drawDotAndShadow = function(x, y) { 
       drawShadow(x - 5, y - 1); 
       drawDot(x, y); 
      } 

      for (var x = 50; x < 70; x ++) { 
       for (var y = 50; y < 58; y ++) { 
        drawDotAndShadow(x, y); 
       } 
      } 
      for (var x = 0; x < 15; x ++) { 
       for (var y = 0; y < x; y ++) { 
        drawDotAndShadow(69 + 15 - x, 54 + y); 
        drawDotAndShadow(69 + 15 - x, 54 - y); 
       } 
      } 

     } 

    </script> 

    <style type="text/css"> 
     #drawing-container { 
      position: absolute; 
      left: 2em; 
      top: 2em; 
      width: 400px; 
      height: 400px; 
      z-index: 2; 
     } 
     #shadow-container { 
      position: absolute; 
      left: 2em; 
      top: 2em; 
      width: 400px; 
      height: 400px; 
      z-index: 1; 
     } 

     #drawing-container img { 
      position: absolute; 
     } 
     #shadow-container img { 
      position: absolute; 
     } 
    </style> 

</head> 
<body onload="javascript:pageload()"> 
    <div id="drawing-container"></div> 
    <div id="shadow-container"></div> 
</body> 
</html> 

Este es el resultado:

alt text

Probablemente, no hay mucho espacio para la optimización, y por supuesto no se habría re ally renderíalo usando javascript de esta manera ... ¿Tal vez puedas encontrar la manera de renderizarlo de manera eficiente en el iPhone? Si es así, ¡házmelo saber!

mejoras posibles:

  • hacer que el centro de la más oscuro círculo sombra (más de opacidad), y el resto más ligero (menos opacidad) para lograr una sombra núcleo.
  • Escala la sombra: hazla un poco más pequeña, para lograr un efecto de profundidad.