Dessiner une forme arrondie UIView avec gradient et de l'ombre portée

EDIT:

J'ai enfin trouvé une vraie solution simple à ce problème, en utilisant le CAGradientLayer de classe, et l'CALayer fonctionnalités de dessin.
Ole Begemann a publié un grand UIView wrapper pour CAGradientLayer classe nommée OBGradientView.
Cette classe permet de créer facilement un gradient de UIView dans votre application.
Ensuite, vous utilisez la CALayer fonctionnalités de dessin pour ajouter des coins arrondis et de l'ombre portée des valeurs :

//Create the gradient view
OBGradientView *gradient = [[OBGradientView alloc] initWithFrame:someRect];
NSArray *colors = [NSArray arrayWithObjects:[UIColor redColor], [UIColor yellowColor], nil];
gradient.colors = colors;

//Set rounded corners and drop shadow
gradient.layer.cornerRadius = 5.0;
gradient.layer.shadowColor = [UIColor grayColor].CGColor;
gradient.layer.shadowOpacity = 1.0;
gradient.layer.shadowOffset = CGSizeMake(2.0, 2.0);
gradient.layer.shadowRadius = 3.0;

[self.view addSubview:gradient];
[gradient release];

N'oubliez pas d'ajouter le QuartzCore cadre de votre projet.

QUESTION D'ORIGINE:

Je travaille sur un contrôle personnalisé qui est un rectangle arrondi bouton, rempli avec un dégradé linéaire, et d'avoir une ombre portée.
J'ai rempli les deux premières étapes à l'aide de cette réponse : texte du lien

Mon problème est maintenant d'ajouter une ombre portée sous la forme obtenue.
En fait, le contexte a été découpée à la forme arrondie rect chemin, de sorte que lorsque j'utilise le CGContextSetShadow fonction, il n'a pas le dessiner.

J'ai essayé de résoudre ce problème par le dessin de la arrondies rect deux fois, d'abord avec une couleur unie, de sorte qu'il attire l'ombre, puis redessiner avec le remplissage en dégradé.

Il un peu travaillé, mais je peut encore voir quelques pixels à l'un des coins de la forme résultant de la première dessiner avec une couleur unie, comme vous pouvez le voir sur cette version agrandie :

http://img269.imageshack.us/img269/6489/capturedcran20100701192.png

C'est presque bon, mais pas encore parfait...

Ici est ma -drawRect: mise en œuvre :

static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight)
{
float fw, fh;
if (ovalWidth == 0 || ovalHeight == 0) {
CGContextAddRect(context, rect);
return;
}
CGContextSaveGState(context);
CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextScaleCTM (context, ovalWidth, ovalHeight);
fw = CGRectGetWidth (rect) / ovalWidth;
fh = CGRectGetHeight (rect) / ovalHeight;
CGContextMoveToPoint(context, fw, fh/2);
CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
CGContextClosePath(context);
CGContextRestoreGState(context);
}
- (void)drawRect:(CGRect)rect
{ 
CGContextRef context = UIGraphicsGetCurrentContext();
CGSize shadowOffset = CGSizeMake(10.0, 10.0);
CGFloat blur = 5.0;
rect.size.width -= shadowOffset.width + blur;
rect.size.height -= shadowOffset.height + blur;
CGContextSaveGState(context);
addRoundedRectToPath(context, rect, _radius, _radius);
CGContextSetShadow (context, shadowOffset, blur);
CGContextDrawPath(context, kCGPathFill);
CGContextRestoreGState(context);
addRoundedRectToPath(context, rect, _radius, _radius);
CGContextClip(context);
CGFloat colors[] =
{
_gradientStartColor.red, _gradientStartColor.green, _gradientStartColor.blue, _gradientStartColor.alpha,
_gradientEndColor.red, _gradientEndColor.green, _gradientEndColor.blue, _gradientEndColor.alpha
};
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(rgb, colors, locations, num_locations);
CGRect currentBounds = self.bounds;
CGPoint gStartPoint = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
CGPoint gEndPoint = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMaxY(currentBounds));
CGContextDrawLinearGradient(context, gradient, gStartPoint, gEndPoint, 0);
CGColorSpaceRelease(rgb);
CGGradientRelease(gradient);
}

Des idées sur la façon de le faire d'une autre manière ?

Merci !

OriginalL'auteur Thomas Desert | 2010-07-01