Comment puis-je dessiner une ombre sous un UIView?

UIView de dessiner une ombre sous le bord inférieur d'un UIView dans Cocoa Touch. Je comprends que je devrais utiliser CGContextSetShadow() pour dessiner l'ombre, mais le guide de programmation Quartz 2D est un peu vague:

  1. Sauvegardez l'état graphique.
  2. Appelez la fonction CGContextSetShadow , en transmettant les valeurs appropriées.
  3. Effectuez tous les dessins auxquels vous voulez appliquer des ombres.
  4. Restaurer l'état graphique

J'ai essayé ce qui suit dans une sous-class UIView :

 - (void)drawRect:(CGRect)rect { CGContextRef currentContext = UIGraphicsGetCurrentContext(); CGContextSaveGState(currentContext); CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5); CGContextRestoreGState(currentContext); [super drawRect: rect]; } 

..mais cela ne marche pas pour moi et je suis un peu coincé sur (a) où aller ensuite et (b) s'il y a quelque chose que je dois faire à mon UIView pour faire ce travail?

Dans votre code actuel, vous enregistrez le GState du context actuel, le configurez pour dessiner une ombre .. et le restaurez à ce qu'il était avant de le configurer pour dessiner une ombre. Ensuite, enfin, vous invoquez l'implémentation de drawRect de la superclass drawRect

Tout dessin qui devrait être affecté par le réglage de l'ombre doit se produire après

 CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5); 

mais avant

 CGContextRestoreGState(currentContext); 

Donc, si vous voulez que le drawRect: de la superclass soit "enveloppé" dans une ombre, alors que diriez-vous si vous réorganisez votre code comme ceci?

 - (void)drawRect:(CGRect)rect { CGContextRef currentContext = UIGraphicsGetCurrentContext(); CGContextSaveGState(currentContext); CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5); [super drawRect: rect]; CGContextRestoreGState(currentContext); } 

Une approche de loin plus simple consiste à définir certains attributes de couche de la vue à l'initialisation:

 self.layer.masksToBounds = NO; self.layer.shadowOffset = CGSizeMake(-15, 20); self.layer.shadowRadius = 5; self.layer.shadowOpacity = 0.5; 

Vous devez importer QuartzCore.

 #import <QuartzCore/QuartzCore.h> 
 self.layer.masksToBounds = NO; self.layer.cornerRadius = 8; // if you like rounded corners self.layer.shadowOffset = CGSizeMake(-15, 20); self.layer.shadowRadius = 5; self.layer.shadowOpacity = 0.5; 

Cela ralentira l'application. L'ajout de la ligne suivante peut améliorer les performances tant que votre vue est visiblement rectangular:

 self.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.bounds].CGPath; 

Même solution, mais juste pour vous callbacker: vous pouvez définir l'ombre directement dans le storyboard.

Ex:

entrez la description de l'image ici

Vous pouvez essayer cela …. vous pouvez jouer avec les valeurs. L' shadowRadius dicte la quantité de flou. shadowOffset dicte où va l'ombre.

Swift 2.0

 let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height)) //Change 2.1 to amount of spread you need and for height replace the code for height demoView.layer.cornerRadius = 2 demoView.layer.shadowColor = UIColor.blackColor().CGColor demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4) //Here you control x and y demoView.layer.shadowOpacity = 0.5 demoView.layer.shadowRadius = 5.0 //Here your control your blur demoView.layer.masksToBounds = false demoView.layer.shadowPath = shadowPath.CGPath 

Swift 3.0

 let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height)) //Change 2.1 to amount of spread you need and for height replace the code for height demoView.layer.cornerRadius = 2 demoView.layer.shadowColor = UIColor.black.cgColor demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4) //Here you control x and y demoView.layer.shadowOpacity = 0.5 demoView.layer.shadowRadius = 5.0 //Here your control your blur demoView.layer.masksToBounds = false demoView.layer.shadowPath = shadowPath.cgPath 

Exemple avec propagation

Exemple avec propagation

Pour créer une ombre de base

  demoView.layer.cornerRadius = 2 demoView.layer.shadowColor = UIColor.blackColor().CGColor demoView.layer.shadowOffset = CGSizeMake(0.5, 4.0); //Here your control your spread demoView.layer.shadowOpacity = 0.5 demoView.layer.shadowRadius = 5.0 //Here your control your blur 

Exemple Basic Shadow dans Swift 2.0

SORTIE

Solution simple et propre à l'aide d'Interface Builder

Ajoutez un file nommé UIView.swift dans votre projet (ou collez-le dans n'importe quel file):

 import UIKit @IBDesignable extension UIView { /* The color of the shadow. Defaults to opaque black. Colors created * from patterns are currently NOT supported. Animatable. */ @IBInspectable var shadowColor: UIColor? { set { layer.shadowColor = newValue!.CGColor } get { if let color = layer.shadowColor { return UIColor(CGColor:color) } else { return nil } } } /* The opacity of the shadow. Defaults to 0. Specifying a value outside the * [0,1] range will give undefined results. Animatable. */ @IBInspectable var shadowOpacity: Float { set { layer.shadowOpacity = newValue } get { return layer.shadowOpacity } } /* The shadow offset. Defaults to (0, -3). Animatable. */ @IBInspectable var shadowOffset: CGPoint { set { layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y) } get { return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height) } } /* The blur radius used to create the shadow. Defaults to 3. Animatable. */ @IBInspectable var shadowRadius: CGFloat { set { layer.shadowRadius = newValue } get { return layer.shadowRadius } } } 

Ensuite, il sera disponible dans Interface Builder pour chaque vue dans le panneau Utilitaires> Inspecteur d'attributes:

Panneau Utilitaires

Vous pouvez facilement définir l'ombre maintenant.

Remarques:
– L'ombre n'apparaîtra pas dans IB, seulement à l'exécution.
– Comme Mazen Kasser a dit

Pour ceux qui n'ont pas réussi à faire en sorte que cela fonctionne […] assurez-vous que Clip Subviews ( clipsToBounds ) n'est pas activé

Je l'utilise dans le cadre de mes utils. Avec cela, nous pouvons non seulement définir l'ombre, mais aussi get un angle arrondi pour n'importe quel UIView . Vous pouvez également définir quelle ombre de couleur vous préférez. Normalement, le noir est préférable, mais parfois, lorsque l'arrière-plan n'est pas blanc, vous pouvez vouloir autre chose. Voici ce que j'utilise –

 in utils.m + (void)roundedLayer:(CALayer *)viewLayer radius:(float)r shadow:(BOOL)s { [viewLayer setMasksToBounds:YES]; [viewLayer setCornerRadius:r]; [viewLayer setBorderColor:[RGB(180, 180, 180) CGColor]]; [viewLayer setBorderWidth:1.0f]; if(s) { [viewLayer setShadowColor:[RGB(0, 0, 0) CGColor]]; [viewLayer setShadowOffset:CGSizeMake(0, 0)]; [viewLayer setShadowOpacity:1]; [viewLayer setShadowRadius:2.0]; } return; } 

Pour l'utiliser, nous devons appeler ceci – [utils roundedLayer:yourview.layer radius:5.0f shadow:YES];

Swift 3

 extension UIView { func installShadow() { layer.cornerRadius = 2 layer.masksToBounds = false layer.shadowColor = UIColor.black.cgColor layer.shadowOffset = CGSize(width: 0, height: 1) layer.shadowOpacity = 0.45 layer.shadowPath = UIBezierPath(rect: bounds).cgPath layer.shadowRadius = 1.0 } } 

Pour ceux qui n'ont pas réussi à faire fonctionner cela (comme moi-même!) Après avoir essayé toutes les réponses ici, assurez-vous que les sous- vues de clip ne sont pas activées à l'inspecteur des attributes …

Swift 3

 self.paddingView.layer.masksToBounds = false self.paddingView.layer.shadowOffset = CGSize(width: -15, height: 10) self.paddingView.layer.shadowRadius = 5 self.paddingView.layer.shadowOpacity = 0.5 

Vous pouvez utiliser ma fonction d'utilité créée pour l'ombre et le rayon d'angle comme ci-dessous:

 - (void)addShadowWithRadius:(CGFloat)shadowRadius withShadowOpacity:(CGFloat)shadowOpacity withShadowOffset:(CGSize)shadowOffset withShadowColor:(UIColor *)shadowColor withCornerRadius:(CGFloat)cornerRadius withBorderColor:(UIColor *)borderColor withBorderWidth:(CGFloat)borderWidth forView:(UIView *)view{ // drop shadow [view.layer setShadowRadius:shadowRadius]; [view.layer setShadowOpacity:shadowOpacity]; [view.layer setShadowOffset:shadowOffset]; [view.layer setShadowColor:shadowColor.CGColor]; // border radius [view.layer setCornerRadius:cornerRadius]; // border [view.layer setBorderColor:borderColor.CGColor]; [view.layer setBorderWidth:borderWidth]; } 

J'espère que cela vous aidera !!!

Tout Répondre bien, mais je veux append un sharepoint plus

Si vous rencontrez un problème lorsque vous avez des cellules de tableau, Deque une nouvelle cellule il y a une incompatibilité dans l'ombre, dans ce cas, vous devez placer votre code fantôme dans une méthode layoutSubviews afin qu'il se comporte bien dans toutes les conditions.

 -(void)layoutSubviews{ [super layoutSubviews]; [self.contentView setNeedsLayout]; [self.contentView layoutIfNeeded]; [VPShadow applyShadowView:self]; } 

ou dans ViewControllers pour une vue spécifique, placez le code fantôme dans la méthode suivante pour que cela fonctionne bien

 -(void)viewDidLayoutSubviews{ [super viewDidLayoutSubviews]; [self.viewShadow layoutIfNeeded]; [VPShadow applyShadowView:self.viewShadow]; } 

J'ai modifié mon implémentation d'ombre pour les nouveaux devs pour une forme plus généralisée ex:

 /*! @brief Add shadow to a view. @param layer CALayer of the view. */ +(void)applyShadowOnView:(CALayer *)layer OffsetX:(CGFloat)x OffsetY:(CGFloat)y blur:(CGFloat)radius opacity:(CGFloat)alpha RoundingCorners:(CGFloat)cornerRadius{ UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:layer.bounds cornerRadius:cornerRadius]; layer.masksToBounds = NO; layer.shadowColor = [UIColor blackColor].CGColor; layer.shadowOffset = CGSizeMake(x,y);// shadow x and y layer.shadowOpacity = alpha; layer.shadowRadius = radius;// blur effect layer.shadowPath = shadowPath.CGPath; }