2010-05-28 18 views
6

A CAShapeLayer utilizza un CGPathRef per disegnare le sue cose. Quindi ho un percorso stellare, e voglio un'ombreggiatura liscia con un raggio di circa 15 unità. Probabilmente ci sono alcune buone funzionalità in alcune nuove versioni di iPhone OS, ma ho bisogno di farlo da solo per una versione vecchia di 3.0 (che la maggior parte delle persone usa ancora).Come disegnare le ombre a discesa in iOS

Ho provato a fare cose DAVVERO spiacevoli: Ho creato un ciclo for e creato sequenzialmente come 15 di quei percorsi, trasformandoli-scalandoli passo dopo passo per diventare più grandi. Quindi assegnandoli a un nuovo CAShapeLayer creato e diminuendoli alfa un po 'su ogni iterazione. Non solo che questo ridimensionamento è matematicamente scorretto e fa schifo (dovrebbe essere relativo al contorno!), L'ombra non è arrotondata e appare davvero brutta. Ecco perché le belle ombre morbide hanno un raggio.

Le punte di una stella non dovrebbero apparire completamente nitide dopo un'ombra di 15 unità. Dovrebbero essere morbidi come la crema. Ma nella mia brutta soluzione sono solo come un'arpa come la stella stessa, dato che tutto ciò che faccio è ridimensionare la stella 15 volte e diminuirla di 15 volte. Brutta.

Mi chiedo come fanno i grandi? Se hai un percorso arbitrario e quel percorso deve gettare un'ombra, come funziona l'algoritmo? Probabilmente il percorso dovrebbe essere espanso come 30 volte, punto per punto rispetto alla tangente del contorno lontano dalla parte riempita, e solo di 0,5 unità per avere una bella fusione.

Prima di re-inventare la ruota, forse qualcuno ha un esempio pratico o un link?

risposta

3

Un'ombra è una maschera traslucida in scala di grigi della forma di un oggetto sfocato e sfalsato.

CGContextSetShadowWithColor e CGContextSetShadow sono come questo viene fatto su iPhone.Si imposta l'ombra quindi si disegna qualcosa e si applica anche un'ombra.

A CAShapeLayer non ha un'opzione facile per applicare un'ombra. Dovrai creare una vista o un livello personalizzato e impostare l'ombra prima di disegnare la forma.

non l'ho provato, ma il seguente potrebbe funzionare:

@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: Grazie Miser.

+0

Per CGContextSetShadow, il secondo parametro deve essere un CGSize, come in CGSizeMake (5,5) –

1

Mi sono posto la stessa domanda. Non sono affatto un esperto su questo argomento, ma ho avuto il seguente pensiero: Fisicamente, un punto del disegno dovrebbe risultare in un'ombra circolare (o ellittica) semitrasparente. Quindi un intero disegno, che consiste in più punti, dovrebbe risultare nella combinazione di molte di queste ombre circolari.

Così ho dipinto un po 'di ombra in Photoshop (strumento pennello, dimensione 7, opacità 33%, colore # 3b3b3b). E 'appena visibile:

alt text

Poi ho scritto un piccolo HTML con Javascript solo per provare e vedere come appare (sicuramente non la tecnica ideale :-):

<!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> 

Questa è la risultato:

alt text

Probabilmente, c'è un sacco di spazio per l'ottimizzazione, e, naturalmente, non sarebbe ri rendilo alleato usando javascript in questo modo ... Forse puoi trovare un modo per renderlo efficiente su iPhone? Se sì, fammi sapere!

possibili miglioramenti:

  • rendere il centro del cerchio più scuro ombra (più opacità), e il resto leggero (meno opacità) per ottenere un'ombra nucleo.
  • Ridimensiona l'ombra: ridurla leggermente, per ottenere un effetto di profondità.
Problemi correlati