2010-02-21 13 views
24

Ho una sottoclasse uiview in cui sto cercando di disegnare un rettangolo arrotondato con un'ombra esterna. Sebbene disegna entrambi gli elementi, posso vedere l'ombra attraverso il riempimento arrotondato del rettangolo. Sono nuovo di CG quindi probabilmente mi manca qualcosa di semplice (anche se non sembra essere l'alfa del riempimento che è impostato su 1). Ecco il codice rect draw.UIView con rettangolo arrotondato e ombra esterna: l'ombra appare sopra il rettangolo

- (void)drawRect:(CGRect)rect { 
    // get the contect 
CGContextRef context = UIGraphicsGetCurrentContext(); 

//for the shadow, save the state then draw the shadow 
CGContextSaveGState(context); 
    CGContextSetShadow(context, CGSizeMake(4,-5), 10); 



//now draw the rounded rectangle 
CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]); 
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0); 

//since I need room in my rect for the shadow, make the rounded rectangle a little smaller than frame 
CGRect rrect = CGRectMake(CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetWidth(rect)-30, CGRectGetHeight(rect)-30); 
CGFloat radius = self.cornerRadius; 
// the rest is pretty much copied from Apples example 
CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect); 
CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect); 

// Start at 1 
CGContextMoveToPoint(context, minx, midy); 
// Add an arc through 2 to 3 
CGContextAddArcToPoint(context, minx, miny, midx, miny, radius); 
// Add an arc through 4 to 5 
CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius); 
// Add an arc through 6 to 7 
CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius); 
// Add an arc through 8 to 9 
CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius); 
// Close the path 
CGContextClosePath(context); 
// Fill & stroke the path 
CGContextDrawPath(context, kCGPathFillStroke); 

//for the shadow 
    CGContextRestoreGState(context); 
} 
+1

leggere questo post del blog http://bynomial.com/blog/?p=52&cpage=1#comment-1115. Risponde come fare questo. –

+0

la soluzione documentata qui è la migliore per me, perché mi mostra come utilizzare un'immagine personalizzata (con maskToBounds = YES) e l'ombra. Grazie! – Mark

+0

@ John: Molte molte grazie per il collegamento, amico ... mi ha aiutato a iniziare. :) – viral

risposta

16

Non penso di poterlo fare in un solo passaggio. Hmm Ho cambiato il tuo codice come segue, che sembra funzionare.

- (void)drawRect:(CGRect)rect 
{ 
    // get the contect 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    //now draw the rounded rectangle 
    CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]); 
    CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 0.0); 

    //since I need room in my rect for the shadow, make the rounded rectangle a little smaller than frame 
    CGRect rrect = CGRectMake(CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetWidth(rect)-30, CGRectGetHeight(rect)-30); 
    CGFloat radius = 45; 
    // the rest is pretty much copied from Apples example 
    CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect); 
    CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect); 

    { 
     //for the shadow, save the state then draw the shadow 
     CGContextSaveGState(context); 

     // Start at 1 
     CGContextMoveToPoint(context, minx, midy); 
     // Add an arc through 2 to 3 
     CGContextAddArcToPoint(context, minx, miny, midx, miny, radius); 
     // Add an arc through 4 to 5 
     CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius); 
     // Add an arc through 6 to 7 
     CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius); 
     // Add an arc through 8 to 9 
     CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius); 
     // Close the path 
     CGContextClosePath(context); 

     CGContextSetShadow(context, CGSizeMake(4,-5), 10); 
     CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]); 

     // Fill & stroke the path 
     CGContextDrawPath(context, kCGPathFillStroke); 

     //for the shadow 
     CGContextRestoreGState(context); 
    } 

    { 
     // Start at 1 
     CGContextMoveToPoint(context, minx, midy); 
     // Add an arc through 2 to 3 
     CGContextAddArcToPoint(context, minx, miny, midx, miny, radius); 
     // Add an arc through 4 to 5 
     CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius); 
     // Add an arc through 6 to 7 
     CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius); 
     // Add an arc through 8 to 9 
     CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius); 
     // Close the path 
     CGContextClosePath(context); 

     CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]); 
     CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);  

     // Fill & stroke the path 
     CGContextDrawPath(context, kCGPathFillStroke); 
    } 
} 
+0

Grande, grazie. Ha molto senso: si disegna il rettangolo, si disegna l'ombra, che è sopra il rettangolo arrotondato, quindi si finisce disegnando di nuovo il rettangolo. Una nota sul tuo codice. Avevo impostato lo sfondo della vista per chiarire nella mia dichiarazione di init. Il codice precedente funziona con qualsiasi altro sfondo, ma con uno sfondo chiaro ho dovuto impostare il colore di riempimento prima che il primo rettangolo venisse sfogliato e riempito. – Martin

+0

Ho letto che è possibile estendere l'area del livello renderizzato in modo che non venga ritagliato dalla cornice della vista. Usa: layer.bounds = CGRectMake (-1, -1,102,102) ... se la tua vista è 100x100 e l'ombra è un offset di pixel ecc. Hai un'idea. –

15

provare questo dopo aver importato QuartzCore/QuartzCore.h

yourView.layer.shadowColor = [[UIColor blackColor] CGColor]; 
yourView.layer.shadowOffset = CGSizeMake(10.0f, 10.0f); 
yourView.layer.shadowOpacity = 1.0f; 
yourView.layer.shadowRadius = 10.0f; 
+1

nota che questo è supportato da iOS 3.2 e sopra solo –

+1

questo non funziona con gli angoli arrotondati usando _maskToBounds e setCornerRadius_. –

+2

Questa soluzione rallenta notevolmente l'intera applicazione ... – Ondrej

39
- (void)drawRect:(CGRect)rect 
{ 
    self.layer.masksToBounds = NO; 
    self.layer.shadowColor = [[UIColor whiteColor] CGColor]; 
    self.layer.shadowOffset = CGSizeMake(0,2); 
    self.layer.shadowRadius = 2; 
    self.layer.shadowOpacity = 0.2; 

    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(20, 20)]; 
    [[UIColor blackColor] setFill]; 

    [path fill]; 
} 
+0

Molto utile, grazie! – Gabriel

+0

L'unico avvertimento qui è assicurarsi che lo sfondo della vista sia impostato su [UIColor clearColor], altrimenti si otterrà l'ombra disegnata attorno alla cornice della vista, ignorando gli angoli arrotondati. – Julian

+2

Non è utile e ridondante impostare proprietà layer in drawRect :, poiché queste non cambiano a meno che non le si modifichi. Sposta quelle chiamate (ad es. In init ...). – millenomi

Problemi correlati