2009-06-15 6 views

Répondre

66

Vous pouvez utiliser CoreGraphics pour créer un chemin pour un rectangle rond avec cet extrait de code:

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); 
} 

Et puis appelez CGContextClip (contexte); pour l'écrêter sur le chemin du rectangle. Maintenant tout dessin effectué, y compris le dessin d'une image, sera coupé à la forme du rectangle rond.

À titre d'exemple, en supposant « image » est un UIImage, ce qui est une méthode drawRect::

CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextSaveGState(context); 
addRoundedRectToPath(context, self.frame, 10, 10); 
CGContextClip(context); 
[image drawInRect:self.frame]; 
CGContextRestoreGState(context); 
+8

up vote parce que les mathématiques est cool – slf

+0

qui semble très utile, mais je ne suis pas au courant la bibliothèque CG. Si j'ai un UIImageView/UIImage, où dois-je aller? – erotsppa

+0

Vous souhaitez implémenter la méthode drawRect sur la vue avec le code que j'ai ajouté ci-dessus. – NilObject

34

Voici une méthode encore plus facile qui est disponible dans l'iPhone 3.0 et plus. Chaque objet basé sur View a une couche associée. Chaque couche peut avoir un ensemble de rayon d'angle, cela vous donnera tout ce que vous voulez:

UIImageView * roundedView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"wood.jpg"]]; 
// Get the Layer of any view 
CALayer * layer = [roundedView layer]; 
[layer setMasksToBounds:YES]; 
[layer setCornerRadius:10.0]; 

// You can even add a border 
[layer setBorderWidth:4.0]; 
[layer setBorderColor:[[UIColor blueColor] CGColor]]; 

Pour utiliser ces méthodes que vous pourriez avoir besoin d'ajouter:

#import <QuartzCore/QuartzCore.h> 
+1

La méthode CoreGraphics ci-dessus publiée par NilObject est plus rapide lorsque vous traitez des éléments animés. Apparemment, le rayon de coin intégré n'est pas aussi efficace. – MagicSeth

+2

Merci! Si quelqu'un rencontre des problèmes, assurez-vous d'importer dans votre fichier d'implémentation, sinon aucune de ces méthodes ne fonctionnera. –

+1

Ici, vous affectez un objet UIImageView. Ce n'est pas une option lorsque vous traitez des images dans UITableViews. – samvermette

2

Voir cette annonce - Très simple réponse

How to set round corners in UI images in iphone

UIImageView * roundedView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"wood.jpg"]]; 
// Get the Layer of any view 
CALayer * l = [roundedView layer]; 
[l setMasksToBounds:YES]; 
[l setCornerRadius:10.0]; 
0

les deux méthodes fonctionnent, mais les différences sho ws en fonction de l'endroit où vous l'utilisez. Par exemple: Si vous avez une vue de table avec les cellules montrant une image avec d'autres étiquettes, etc., et que vous utilisez layer pour définir le coinRadius, le défilement prendra un grand succès. Ça devient saccadé.

J'ai fait face à ce problème lorsque j'utilisais le calque pour une image dans une cellule de vue de table et j'essayais de comprendre la cause de cette saccades pour constater que CALayer était le coupable.

Utilisé la première solution de faire les choses dans drawRect expliqué par NilObject. Cela fonctionne comme un charme avec défilement étant lisse comme de la soie. D'un autre côté, si vous voulez utiliser ceci dans des vues statiques comme la vue popover, etc., la couche est la façon la plus simple de le faire. Comme je l'ai dit, les deux méthodes fonctionnent bien que vous devez décider en fonction de l'endroit où vous voulez l'utiliser.

0

J'utilise cette méthode.

+ (UIImage *)imageWithColor:(UIColor *)color andSize:(CGSize)size; 
    { 
     UIImage *img = nil; 


     CGRect rect = CGRectMake(0, 0, size.width, size.height); 
     UIGraphicsBeginImageContext(rect.size); 
     CGContextRef context = UIGraphicsGetCurrentContext(); 
     CGContextSetFillColorWithColor(context, 
            color.CGColor); 
     CGContextFillRect(context, rect); 
     img = UIGraphicsGetImageFromCurrentImageContext(); 

     UIGraphicsEndImageContext(); 


     return img; 
    } 
+2

Selon les règles de gestion de la mémoire, l'objet image renvoyé par 'UIGraphicsGetImageFromCurrentImageContext' n'a pas besoin d'être conservé, ce qui signifie qu'il y aurait une fuite de mémoire. C'est l'appelant de 'imageWithColor' qui doit le conserver. Peut-être avez-vous ajouté le conservateur à cause du NSAutoreelasePool (qui semble également suspect)? –

15

Je sais que c'est de vieilles nouvelles, mais juste pour la faire bouillir un peu:

Il y a deux questions possibles ici: (1) comment puis-je appliquer des coins arrondis à un UIView (comme un UIImageView), qui sera affiché à l'écran, et (2) comment masquer une image carrée (c'est-à-dire un UIImage) pour produire une nouvelle image avec des coins arrondis. Pour (1), la méthode la plus simple consiste à utiliser CoreAnimation et à définir la couche view.layer.cornerRadius propriété

// Because we're using CoreAnimation, we must include QuartzCore.h 
// and link QuartzCore.framework in a build phases 
#import <QuartzCore/QuartzCore.h> 

// start with an image 
UIImage * fooImage = [UIImage imageNamed:@"foo.png"]; 
// put it in a UIImageView 
UIView * view = [UIImageView alloc] initWithImage:fooImage]; 
// round its corners. This mask now applies to the view's layer's *background* 
view.layer.cornerRadius = 10.f 
// enable masksToBounds, so the mask applies to its foreground, the image 
view.layer.masksToBounds = YES; 

Pour (2), la meilleure façon est d'utiliser les opérations graphiques UIKit:

// start with an image 
UIImage * fooImage = [UIImage imageNamed:@"foo.png"]; 
CGRect imageRect = CGRectMake(0, 0, fooImage.size.width, fooImage.size.height); 
// set the implicit graphics context ("canvas") to a bitmap context for images 
UIGraphicsBeginImageContextWithOptions(imageRect.size,NO,0.0); 
// create a bezier path defining rounded corners 
UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:10.f]; 
// use this path for clipping in the implicit context 
[path addClip]; 
// draw the image into the implicit context 
[fooImage drawInRect:imageRect]; 
// save the clipped image from the implicit context into an image 
UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext(); 
// cleanup 
UIGraphicsEndImageContext(); 

Ce qui est délicat au sujet de problème (2) est que vous pourriez penser que vous pourriez faire l'opération en utilisant la propriété view.layer.mask dans CoreAnimation. Mais vous ne pouvez pas parce que la méthode CALayer renderInContext:, que vous utiliseriez pour générer un UIImage à partir de la couche masquée, semble ignorer le masque. Pire, la documentation pour renderInContext: ne mentionne pas cela, et fait seulement allusion au comportement pour OSX 10.5. Un autre contexte: l'approche ci-dessus de (2) utilise les wrappers de UIKit autour de fonctionnalités CoreGraphics plus basiques. Vous pouvez faire la même chose en utilisant directement les appels CoreGraphics - c'est ce que la réponse choisie est en train de faire - mais ensuite vous devez construire le chemin rectiligne arrondi manuellement à partir des courbes et des lignes et vous devez également compenser le fait que CoreGraphics utilise un dessin système de coordonnées qui est retourné par rapport à UIKit.

+0

Tout en travaillant bien, reflète l'image horizontalement. J'ai supprimé le CGContextDrawImage ((ctx, imageRect, theImage.CGImage), et l'a remplacé par un [theImage drawInRect: CGRectMake (0,0, imageRect.size.width, imageRect.size.height)], et cela a résolu le problème. – zachron

+0

@zachron merci pour la correction J'ai réécrit cette réponse pour éviter complètement le CG brut.Cela semble recommandé basé sur la lecture de la section "Dessin avec Quartz et UIKit" dans http://developer.apple.com/library/ios/#documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html – algal

1

Très simple. self.profileImageView.layer.cornerRadius = self.profileImageView.frame.size.width/2; self.profileImageView.clipsToBounds = YES;

Pour chaque vue, il existe une propriété de calque groupée. Ainsi, la première ligne de ce qui précède est de définir le rayon de coin de l'objet de couche (c'est-à-dire une instance de classe CALayer). Pour créer une image circulaire à partir d'une image au carré, le rayon est défini sur la moitié de la largeur de UIImageView. Par exemple, si la largeur de l'image au carré est de 100 pixels. Le rayon est défini sur 50 pixels. Deuxièmement, vous devez définir la propriété clipsToBounds sur YES pour que le calque fonctionne.

0

bâtiment hors de algal, voici les méthodes de couple qui sont agréables à mettre dans une catégorie UIImage:


- (UIImage *) roundedCornerImageWithRadius:(CGFloat)radius 
{ 
    CGRect imageRect = CGRectMake(0, 0, self.size.width, self.size.height); 
    UIGraphicsBeginImageContextWithOptions(imageRect.size,NO,0.0); //scale 0 yields better results 

    //create a bezier path defining rounded corners and use it for clippping 
    UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:radius]; 
    [path addClip]; 

    // draw the image into the implicit context 
    [self drawInRect:imageRect]; 

    // get image and cleanup 
    UIImage *roundedCornerImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return roundedCornerImage; 
} 

+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size andCornerRadius:(CGFloat)radius 
{ 
    UIImage *image = nil; 
    if (size.width == 0 || size.height == 0) { 
     size = CGSizeMake(1.0, 1.0); 
    } 
    CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height); 
    UIGraphicsBeginImageContextWithOptions(rect.size,NO,0.0); //yields sharper results than UIGraphicsBeginImageContext(rect.size) 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    if (context) 
    { 
     CGContextSetFillColorWithColor(context, [color CGColor]); 
     if (radius > 0.0) { 
      //create a bezier path defining rounded corners and use it for clippping 
      UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius]; 
      [path addClip]; 
      CGContextAddPath(context, path.CGPath); 
     } 
     CGContextFillRect(context, rect); 
     image = UIGraphicsGetImageFromCurrentImageContext(); 
     UIGraphicsEndImageContext(); 
    } 
    return image; 
} 
Questions connexes