2010-02-21 17 views
24

ich eine UIView-Unterklasse habe, wo ich versuche, ein abgerundetes Rechteck mit einem Schlagschatten zu ziehen. Obwohl es beide Elemente zeichnet, kann ich Schatten durch die abgerundete Rechteckfüllung sehen. Ich bin neu in CG, also vermisse ich wahrscheinlich etwas Einfaches (obwohl es nicht das Alpha der Füllung zu sein scheint, das auf 1 gesetzt ist). Hier ist der Zeichenrect-Code.UIView mit abgerundetem Rechteck und Schlagschatten: Schatten erscheint über Rechteck

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

dieses Blog-Post lesen http://bynomial.com/blog/?p=52&cpage=1#comment-1115. Es beantwortet wie man das macht. –

+0

Die hier dokumentierte Lösung ist die beste für mich, weil sie mir zeigt, wie man ein benutzerdefiniertes Bild (mit maskToBounds = YES) sowie den Schatten verwendet. Vielen Dank! – Mark

+0

@John: Vielen vielen Dank für den Link, Kumpel ... Hat mir geholfen, zu starten. :) – viral

Antwort

16

Ich glaube nicht, dass Sie dies in einem einzigen Durchgang tun können. Hmm ich habe deinen Code wie folgt geändert, was zu funktionieren scheint.

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

Großartig, danke. Macht viel Sinn: Sie zeichnen das Rechteck, zeichnen den Schatten, der über dem abgerundeten Rechteck liegt, damit Sie das Rechteck wieder zeichnen. Eine Anmerkung zu Ihrem Code. Ich hatte den Hintergrund der Sicht in meiner init-Erklärung klargestellt. Der obige Code funktioniert mit jedem anderen Hintergrund, aber mit einem klaren Hintergrund musste ich die Füllfarbe einstellen, bevor das erste Rechteck gestrichen und gefüllt wird. – Martin

+0

Ich lese, dass Sie den Bereich der gerenderten Ebene erweitern können, so dass es nicht vom Ansichtsrahmen abgeschnitten wird. Verwenden Sie: layer.bounds = CGRectMake (-1, -1,102,102) ... wenn Ihre Ansicht 100x100 ist und der Schatten ein Pixel-Offset ist usw. Sie erhalten die Idee. –

15

Versuchen Sie dies, nachdem Sie importieren 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

Beachten Sie, dass dies von iOS 3.2 und höher unterstützt wird nur –

+1

Dies funktioniert nicht mit abgerundeten Ecken mit _maskToBounds und setCornerRadius_. –

+2

Diese Lösung verlangsamt die gesamte Anwendung merklich ... – 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

Sehr hilfreich, danke! – Gabriel

+0

Der einzige Nachteil hierbei ist, dass der Hintergrund Ihrer Ansicht auf [UIColor clearColor] eingestellt ist. Andernfalls wird Ihr Schatten um den Rahmen der Ansicht herum gezeichnet, wobei die abgerundeten Ecken ignoriert werden. – Julian

+2

Es ist nicht sinnvoll und redundant, Layer-Eigenschaften in drawRect: zu setzen, da diese sich nur ändern, wenn Sie sie ändern. Verschieben Sie diese Anrufe (z. B. in init ...). – millenomi