451 votes

UIView avec coins arrondis et ombre portée ?

Je travaille sur une application depuis quelques années et j'ai reçu une demande de conception simple : Arrondir les coins d'une UIView et ajouter une ombre portée.

Je veux un UIView ... : Je voulais juste une vue blanche vierge avec des coins arrondis et une légère ombre portée (sans effet de lumière). Je peux faire chacun de ces éléments un par un mais l'habituel... clipToBounds / maskToBounds les conflits se produisent.

enter image description here

1 votes

Puisque vous dites dans un commentaire ci-dessous que vous avez obtenu ce résultat en utilisant CoreGraphics, pourriez-vous partager la réponse avec la communauté afin d'aider les autres dans la même situation, comme ils ont essayé de vous aider ?

0 votes

Je suis désolé, c'était il y a longtemps, et je n'ai plus la source. Ce que j'ai fait, c'est surcharger -drawRect : et utiliser UIBezierPath pour dessiner un rectangle, et appliquer une ombre au calque derrière la vue... si je me souviens bien. :)

6 votes

La réponse acceptée ne fonctionne pas !

464voto

Evan Mulawski Points 28536

Le code suivant permet d'ajouter une bordure, un rayon de bordure et une ombre portée à l'image de l'utilisateur. v , a UIView :

// border radius
[v.layer setCornerRadius:30.0f];

// border
[v.layer setBorderColor:[UIColor lightGrayColor].CGColor];
[v.layer setBorderWidth:1.5f];

// drop shadow
[v.layer setShadowColor:[UIColor blackColor].CGColor];
[v.layer setShadowOpacity:0.8];
[v.layer setShadowRadius:3.0];
[v.layer setShadowOffset:CGSizeMake(2.0, 2.0)];

Vous pouvez ajuster les paramètres en fonction de vos besoins.

De plus, ajoutez le framework QuartzCore à votre projet et :

#import <QuartzCore/QuartzCore.h>

Voir mon autre réponse concernant masksToBounds .


Note

Cela peut ne pas fonctionner dans tous les cas. Si vous constatez que cette méthode interfère avec d'autres opérations de dessin que vous effectuez, veuillez consulter la rubrique cette réponse .

90 votes

Le problème, c'est que lorsque je définis le rayon des coins, cela définit maskToBounds : YES, alors que l'ombre nécessite clipToBounds : NO (où clipToBounds fait la même chose que maskToBounds).

15 votes

Même problème ici. Si j'ai une couleur d'arrière-plan, je veux qu'elle soit coupée aux coins arrondis. Pour cela, je dois utiliser maskToBounds=TRUE, mais alors l'ombre disparaît

3 votes

Pour les débutants comme moi : J'ai dû importer le framework QuartzCore dans mon projet afin d'appeler des méthodes sur l'objet layer.

80voto

David C. Points 321

Une façon d'y parvenir est de placer la vue avec des coins arrondis dans une vue avec l'ombre portée.

UIView* roundedView = [[UIView alloc] initWithFrame: frame];
roundedView.layer.cornerRadius = 5.0;
roundedView.layer.masksToBounds = YES;

UIView* shadowView = [[UIView alloc] initWithFrame: frame];
shadowView.layer.shadowColor = [UIColor blackColor].CGColor;
shadowView.layer.shadowRadius = 5.0;
shadowView.layer.shadowOffset = CGSizeMake(3.0, 3.0);
shadowView.layer.shadowOpacity = 1.0;
[shadowView addSubview: roundedView];

Vous pouvez ensuite ajouter le shadowView où vous voulez.

7 votes

Amit, vous devez définir maskToBounds/clipToBounds = YES pour le * roundedView seulement *. NE PAS définir cela pour la shadowView. Je n'ai pas essayé le code ci-dessus mais je suis sûr que cette solution fonctionne, même si elle n'est pas idéale. Le shadowRadius plus élevé prend en charge les zones de rayon de coin. Réglez le shadowRadius à 0 ou 1 et vous remarquerez ce que j'essaie de dire.

2 votes

Il manque quelque chose comme shadowView.layer.shadowOpacity = 0.6 ;.

3 votes

"shadowView.layer.opacity = 1.0" devrait être "shadowView.layer.shadowOpacity = 1.0".

27voto

Alex Stone Points 8138

J'ai résolu le problème en utilisant l'astuce suivante lors de l'attribution du chemin d'ombre pour la vue du conteneur :

[UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12]

Remarquez que le chemin donné à l'ombre est un rectangle arrondi avec le même rayon de coin que l'arrière-plan que la cellule contient :

//this is the border for the UIView that is added to a cell
cell.backgroundView.layer.cornerRadius = 12;
cell.backgroundView.layer.masksToBounds = YES;
cell.backgroundView.layer.borderColor = [UIColor darkGrayColor].CGColor;
cell.backgroundView.layer.borderWidth = 1;

//this is the shadow around the cell itself (cannot have round corners with borders and shadow, need to use two views
cell.layer.shadowRadius = 2;
cell.layer.cornerRadius = 12;
cell.layer.masksToBounds = NO;
[[cell layer] setShadowColor:[[UIColor darkGrayColor] CGColor]];

[[cell layer] setShadowOffset:CGSizeMake(0.0,0.0)];
[[cell layer] setShadowOpacity:1.0];

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12];
[[cell layer] setShadowPath:[path CGPath]];

0 votes

Meilleure réponse parce qu'elle explique la bonne façon d'ajouter de l'ombre à une vue aux coins arrondis. Merci @Alex Stone

16voto

daniel.gindi Points 1065

Si vous avez du mal à cause de l'arrondi corners vs. subviews vs. masksToBounds alors essayez d'utiliser ma fonction :

- (UIView*)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andRadius:(CGFloat)shadowRadius andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame; // Modify this if needed
    shadowFrame.size.width = 0.f;
    shadowFrame.size.height = 0.f;
    shadowFrame.origin.x = 0.f;
    shadowFrame.origin.y = 0.f;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];
    shadow.userInteractionEnabled = NO; // Modify this if needed
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = shadowRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;
    [view.superview insertSubview:shadow belowSubview:view];
    [shadow addSubview:view];
    return shadow;
}

Appelez-la sur votre vue. Que votre vue ait des coins arrondis, quelle que soit sa taille ou sa forme, une belle ombre sera dessinée.

Conservez simplement la valeur de retour de la fonction afin de pouvoir vous y référer lorsque vous voudrez supprimer le tableau (ou par exemple en utilisant insertSubview:aboveView: )

0 votes

Il fonctionne bien. Mais si la vue a des reconnaissances de gestes, alors cela ne fonctionnera pas. comment pouvons-nous le résoudre ?

0 votes

@manujmv Voyez-vous les lignes où "// Modifiez ceci si nécessaire" est spécifié ? C'est ce dont vous avez besoin. shadow.userInteractionEnabled = YES ;

0 votes

@manujmv alors vous devriez tester les cadres de la vue et de la sous-vue pour voir pourquoi. Il y a probablement quelque chose qui ne va pas ici. Ce code exact fonctionne pour moi dans de très belles applications.

6voto

Zayin Krige Points 1029

J'ai créé une aide sur UIView

@interface UIView (Helper)

- (void)roundCornerswithRadius:(float)cornerRadius
               andShadowOffset:(float)shadowOffset;
@end

vous pouvez l'appeler comme ceci

[self.view roundCornerswithRadius:5 andShadowOffset:5];

Voici l'implémentation

- (void)roundCornerswithRadius:(float)cornerRadius
               andShadowOffset:(float)shadowOffset
{
    const float CORNER_RADIUS = cornerRadius;
    const float SHADOW_OFFSET = shadowOffset;
    const float SHADOW_OPACITY = 0.5;
    const float SHADOW_RADIUS = 3.0;

    UIView *superView = self.superview;

    CGRect oldBackgroundFrame = self.frame;
    [self removeFromSuperview];

    CGRect frameForShadowView = CGRectMake(0, 0, oldBackgroundFrame.size.width, oldBackgroundFrame.size.height);
    UIView *shadowView = [[UIView alloc] initWithFrame:frameForShadowView];
    [shadowView.layer setShadowOpacity:SHADOW_OPACITY];
    [shadowView.layer setShadowRadius:SHADOW_RADIUS];
    [shadowView.layer setShadowOffset:CGSizeMake(SHADOW_OFFSET, SHADOW_OFFSET)];

    [self.layer setCornerRadius:CORNER_RADIUS];
    [self.layer setMasksToBounds:YES];

    [shadowView addSubview:self];
    [superView addSubview:shadowView];

}

2 votes

C'est une bonne solution élégante. Assurez-vous que votre vue a été ajoutée à sa vue supérieure avant de l'utiliser. J'ai ajouté quelques paramètres pour me donner plus de contrôle sur l'ombre, mais dans l'ensemble, cela fonctionne parfaitement. Merci !

1 votes

C'est une bonne solution, mais elle ne fonctionne pas avec autolayout : la vue sera dessinée à l'origine 0,0.

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