125 votes

Arrondis UIView en utilisant CALayers - seulement quelques coins - comment ?

Dans mon application il y a quatre boutons nommés comme suit.

  • En haut à gauche
  • En bas à gauche
  • En haut à droite
  • En bas à droite

Au-dessus de ce bouton, il est une image de la vue / ou nous pouvons utiliser aussi UIView.

Maintenant, supposons que l'utilisateur appuie sur bouton en haut à gauche. L'image ci-dessus / vue doit être arrondi à partir de ce coin particulier.

Je vais avoir quelques difficultés dans l'application des coins arrondis à l'UIView.

Maintenant je suis à l'aide de code suivant pour appliquer les coins arrondis à chaque angle de vue. Elle est ici.

    // imgVUserImg is a image view on IB.
    imgVUserImg.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"any Url Here"];
    CALayer *l = [imgVUserImg layer];
    [l setMasksToBounds:YES];
    [l setCornerRadius:5.0];  
    [l setBorderWidth:2.0];
    [l setBorderColor:[[UIColor darkGrayColor] CGColor]];

Le code ci-dessus est l'application de la rondeur à chacun des angles de Vue. Au lieu de cela, je voulais juste appliquer la rondeur à certains coins comme - haut / haut+gauche / bas+droite etc.

Est-il possible ? SI oui, Comment?

Merci d'avance pour le partage de vos connaissances.

Sagar.

358voto

Stuart Points 8578

Départ dans iOS 3.2, vous pouvez utiliser la fonctionnalité d' UIBezierPaths pour créer un out-of-the-box arrondie rect (où seuls les coins sont arrondis). Vous pouvez ensuite utiliser ce que le chemin de CAShapeLayer, et de l'utiliser comme un masque pour votre vue de la couche:

// Create the path (with only the top-left corner rounded)
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds 
                                               byRoundingCorners:UIRectCornerTopLeft
                                                     cornerRadii:CGSizeMake(10.0, 10.0)];

// Create the shape layer and set its path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = imageView.bounds;
maskLayer.path = maskPath.CGPath;

// Set the newly created shape layer as the mask for the image view's layer
imageView.layer.mask = maskLayer;

Et c'est tout - pas de déconner définir manuellement des formes Graphiques de Base, pas de création de masquage des images dans Photoshop. La couche n'a même pas besoin d'invalider. L'application de l'angle arrondi ou changer de coin est aussi simple que la définition d'un nouveau UIBezierPath et à l'aide de son CGPath que le masque de calque. L' corners paramètre de l' bezierPathWithRoundedRect:byRoundingCorners:cornerRadii: méthode est un masque de bits, et donc de plusieurs coins arrondis par le joint torique ensemble.


EDIT: Ajout d'une ombre

Si vous cherchez à ajouter une ombre à ce, un peu plus de travail est nécessaire.

Parce que "imageView.layer.mask = maskLayer" applique un masque, une ombre ne sera pas ordinairement montrer à l'extérieur. L'astuce est d'utiliser une vue transparente, puis ajouter deux sous-couches (CALayers) à la vue de la couche: shadowLayer et roundedLayer. Les deux besoin de faire usage de l' UIBezierPath. L'image est ajoutée comme le contenu de roundedLayer.

// Create a transparent view
UIView *theView = [[UIView alloc] initWithFrame:theFrame];
[theView setBackgroundColor:[UIColor clearColor]];

// Create the path (with only the top-left corner rounded)
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:theView.bounds 
                                               byRoundingCorners:UIRectCornerTopLeft
                                                     cornerRadii:CGSizeMake(10.0f, 10.0f)];

// Create the shadow layer
CAShapeLayer *shadowLayer = [CAShapeLayer layer];
[shadowLayer setFrame:theView.bounds];
[shadowLayer setMasksToBounds:NO];
[shadowLayer setShadowPath:maskPath.CGPath];
// ...
// Set the shadowColor, shadowOffset, shadowOpacity & shadowRadius as required
// ...

// Create the rounded layer, and mask it using the rounded mask layer
CALayer *roundedLayer = [CALayer layer];
[roundedLayer setFrame:theView.bounds];
[roundedLayer setContents:(id)theImage.CGImage];

CAShapeLayer *maskLayer = [CAShapeLayer layer];
[maskLayer setFrame:theView.bounds];
[maskLayer setPath:maskPath.CGPath];

roundedLayer.mask = maskLayer;

// Add these two layers as sublayers to the view
[theView.layer addSublayer:shadowLayer];
[theView.layer addSublayer:roundedLayer];

45voto

nevan king Points 46410

J'ai utilisé la réponse sur au Comment puis-je créer un rond acculé UILabel sur l'iPhone? et le code de la Façon dont est arrondi rect vue avec la transparence fait sur l'iphone? pour rendre ce code.

Puis j'ai réalisé que j'avais répondu à la mauvaise question (a donné un arrondi UILabel au lieu de UIImage) alors j'ai utilisé ce code pour le modifier:

http://discussions.apple.com/thread.jspa?threadID=1683876

Faire un iPhone projet avec le modèle de Vue. De l'avis du contrôleur, ajoutez ceci:

- (void)viewDidLoad
{
    CGRect rect = CGRectMake(10, 10, 200, 100);
    MyView *myView = [[MyView alloc] initWithFrame:rect];
    [self.view addSubview:myView];
    [super viewDidLoad];
}

MyView est juste un UIImageView sous-classe:

@interface MyView : UIImageView
{
}

Je n'avais jamais utilisé les graphiques des contextes avant, mais j'ai réussi à entraver ensemble de ce code. Il manque le code pour deux des coins. Si vous lisez le code, vous pouvez voir comment j'ai mis en place ce (en supprimant certains de l' CGContextAddArc des appels, et la suppression de certaines des valeurs de rayon dans le code. Le code de tous les coins est là, afin de l'utiliser comme un point de départ et supprimer les parties qui créent des coins, vous n'avez pas besoin. Notez que vous pouvez faire des rectangles avec 2 ou 3 coins arrondis si vous le souhaitez.

Le code n'est pas parfait, mais je suis sûr que vous pouvez la ranger un peu.

static void addRoundedRectToPath(CGContextRef context, CGRect rect, float radius, int roundedCornerPosition)
{

    // all corners rounded
    //  CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius);
    //  CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius);
    //  CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, 
    //                  radius, M_PI / 4, M_PI / 2, 1);
    //  CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - radius, 
    //                          rect.origin.y + rect.size.height);
    //  CGContextAddArc(context, rect.origin.x + rect.size.width - radius, 
    //                  rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1);
    //  CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + radius);
    //  CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, 
    //                  radius, 0.0f, -M_PI / 2, 1);
    //  CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y);
    //  CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius, 
    //                  -M_PI / 2, M_PI, 1);

    // top left
    if (roundedCornerPosition == 1) {
        CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius);
        CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius);
        CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, 
                        radius, M_PI / 4, M_PI / 2, 1);
        CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, 
                                rect.origin.y + rect.size.height);
        CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y);
        CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y);
    }   

    // bottom left
    if (roundedCornerPosition == 2) {
        CGContextMoveToPoint(context, rect.origin.x, rect.origin.y);
        CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height);
        CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, 
                                rect.origin.y + rect.size.height);
        CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y);
        CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y);
        CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius, 
                        -M_PI / 2, M_PI, 1);
    }

    // add the other corners here


    CGContextClosePath(context);
    CGContextRestoreGState(context);
}


-(UIImage *)setImage
{
    UIImage *img = [UIImage imageNamed:@"my_image.png"];
    int w = img.size.width;
    int h = img.size.height;

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);

    CGContextBeginPath(context);
    CGRect rect = CGRectMake(0, 0, w, h);


    addRoundedRectToPath(context, rect, 50, 1);
    CGContextClosePath(context);
    CGContextClip(context);

    CGContextDrawImage(context, rect, img.CGImage);

    CGImageRef imageMasked = CGBitmapContextCreateImage(context);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    [img release];

    return [UIImage imageWithCGImage:imageMasked];
}

alt text

N'oubliez pas que vous aurez besoin pour obtenir le QuartzCore cadre là que pour que cela fonctionne.

18voto

itsaboutcode Points 4818

J'ai utilisé ce code à de nombreux endroits dans mon code et cela fonctionne correctement à 100%. Vous pouvez changer n'importe quel corder en changeant une propriété "byRoundingCorners: UIRectCornerBottomLeft"

 UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:UIRectCornerBottomLeft cornerRadii:CGSizeMake(10.0, 10.0)];

                CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
                maskLayer.frame = view.bounds;
                maskLayer.path = maskPath.CGPath;
                view.layer.mask = maskLayer;
                [maskLayer release];
 

5voto

aZtraL-EnForceR Points 419

Stuarts exemple pour arrondir des coins spécifiques fonctionne très bien. Si vous voulez arrondir plusieurs coins comme en haut à gauche et à droite, voici comment faire

 // Create the path (with only the top-left corner rounded)
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageview
                                               byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight
                                                     cornerRadii:CGSizeMake(10.0, 10.0)];

// Create the shape layer and set its path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = imageview.bounds;
maskLayer.path = maskPath.CGPath;

// Set the newly created shape layer as the mask for the image view's layer
imageview.layer.mask = maskLayer; 
 

3voto

MrMage Points 4695

Voir cette question. Vous devez dessiner votre propre rectangle CGPath avec certains coins arrondis, ajouter l' CGPath votre CGContext , puis extrait à l'aide d' CGContextClip.

Vous pouvez également tracer l'arrondi rect avec les valeurs alpha d'une image et d'utiliser cette image pour créer un nouveau calque qui vous définissez comme votre calque mask de la propriété (voir la documentation d'Apple).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X