Comment masquer une image carrée en une image à coins arrondis?
Vous pouvez utiliser CoreGraphics pour créer un chemin pour un rectangle arrondi 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 appelez ensuite CGContextClip (context); pour le couper sur le chemin rectangle. Désormais, tout dessin effectué, y compris le dessin d’une image, sera découpé dans un rectangle arrondi.
Par exemple, en supposant que "image" est un UIImage, et ceci dans une méthode drawRect:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
addRoundedRectToPath(context, self.frame, 10, 10);
CGContextClip(context);
[image drawInRect:self.frame];
CGContextRestoreGState(context);
Voici une méthode encore plus simple disponible dans iPhone 3.0 et versions ultérieures. Chaque objet basé sur une vue est associé à une couche. Chaque couche peut avoir un rayon de coin défini, cela vous donnera exactement 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, vous devrez peut-être ajouter:
#import <QuartzCore/QuartzCore.h>
Je me rends compte que c’est une vieille nouvelle, mais pour résumer un peu:
Il y a deux questions possibles ici: (1) comment appliquer des angles arrondis à une vue UIV (telle qu’un UIImageView), qui sera affichée à l’écran, et (2) comment masquer une image carrée (qui est un UIImage) pour produire une nouvelle image avec des coins arrondis.
Pour (1), le cours le plus simple consiste à utiliser CoreAnimation et à définir la propriété view.layer.cornerRadius.
// 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), le meilleur moyen consiste à 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();
Le problème avec le problème (2) est que vous pourriez penser que vous pourriez effectuer toute l'opération à l'aide de la propriété view.layer.mask dans CoreAnimation. Mais vous ne pouvez pas, car la méthode CALayer renderInContext:
, que vous utiliseriez pour générer un UIImage à partir du calque masqué, semble ignorer le masque. Pire encore, la documentation de renderInContext:
ne le mentionne pas et fait seulement allusion au comportement de OSX 10.5.
Un contexte supplémentaire: l’approche ci-dessus de (2) utilise les wrappers d’UIKit autour de fonctionnalités plus fondamentales de CoreGraphics. Vous pouvez faire la même chose en utilisant directement les appels CoreGraphics - c’est ce que fait la réponse choisie - mais vous devez ensuite créer manuellement le chemin arrondi de bezier à partir de courbes et de lignes et vous devez également compenser le fait que CoreGraphics utilise une système de coordonnées de dessin inversé par rapport à UIKit.
Voir cet article - Réponse très simple
Comment définir des angles arrondis dans les images d'interface utilisateur dans l'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];
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 couche intégrée. La première ligne de ce qui précède consiste donc à définir le rayon de coin de l’objet calque (c’est-à-dire une instance de la 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.
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;
}
Construisant à partir de algal , voici quelques méthodes qui sont bien à 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;
}
Les deux méthodes fonctionnent, mais les différences apparaissent selon l'endroit où vous les utilisez.
Pour Ex: si vous avez une vue sous forme de tableau avec les cellules montrant une image avec d'autres étiquettes, etc., et que vous utilisez un calque pour définir le cornerRadius, le défilement aura un impact important. Ça devient saccadé.
J'ai rencontré ce problème lorsque j'utilisais Layer pour une image dans une cellule de vue tableau et que j'essayais de comprendre la cause de ce saccage avant de découvrir 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 le défilement étant lisse comme de la soie.
D'autre part, si vous souhaitez utiliser cette option dans des vues statiques telles que la vue contextuelle, etc., le calque est le moyen le plus simple de le faire.
Comme je l'ai dit, les deux méthodes fonctionnent bien, mais vous devez décider en fonction de l'endroit où vous souhaitez les utiliser.