Why does masksToBounds = YES prevent the shadow of CALayer?

With the following snippet, I add a shadow effect for one of my UIView. It works very well. But as soon as I set the masksToBounds property to the YES view. The shadow shadow effect is no longer displayed.

self.myView.layer.shadowColor = [[UIColor blackColor] CGColor]; self.myView.layer.shadowOpacity = 1.0; self.myView.layer.shadowRadius = 10.0; self.myView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f); self.myView.layer.cornerRadius = 5.0; self.myView.layer.masksToBounds = YES; // <-- This is causing the Drop shadow to not be rendered UIBezierPath *path = [UIBezierPath bezierPathWithCurvedShadowForRect:self.myView.bounds]; self.myView.layer.shadowPath = path.CGPath; self.myView.layer.shouldRasterize = YES; 

Do you have any ideas on this?

+75
ios objective-c calayer uiview
Sep 11 '10 at 12:22
source share
6 answers

Since the shadow is an effect made outside of the view, and that the masksToBounds set to YES tells UIView not to draw anything outside of itself.

If you want to view a roundedCorner with a shadow, I suggest you do this in two ways:

 UIView *view1 = [[UIView alloc] init]; UIView *view2 = [[UIView alloc] init]; view1.layer.cornerRadius = 5.0; view1.layer.masksToBounds = YES; view2.layer.cornerRadius = 5.0; view2.layer.shadowColor = [[UIColor blackColor] CGColor]; view2.layer.shadowOpacity = 1.0; view2.layer.shadowRadius = 10.0; view2.layer.shadowOffset = CGSizeMake(0.0f, 0.0f); [view2 addSubview:view1]; [view1 release]; 
+151
Sep 11 '10 at 13:04 on
source share

Now this is iOS 6, everything could change. TheSquad's answer doesn't work for me until I managed to add another line view2.layer.masksToBounds = NO; otherwise the shadow will not be displayed. Although the documentation says that masksToBounds NOT the default, my code shows the opposite.

This is how I make a rounded corner button with a shadow, which is one of the most commonly used code snippets in my application.

 button.layer.masksToBounds = YES; button.layer.cornerRadius = 10.0f; view.layer.masksToBounds = NO; // critical to add this line view.layer.cornerRadius = 10.0f; view.layer.shadowOpacity = 1.0f; // set shadow path to prevent horrible performance view.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:_button.bounds cornerRadius:10.0f].CGPath; [view addSubview:button]; 

EDIT

If the views need to be animated or scrolled, masksToBounds = YES tax performance is significant, which means that the animation is likely to stutter. To get a rounded corner and shadow AND smooth animation or scrolling, use the following code instead:

 button.backgroundColor = [UIColor clearColor]; button.layer.backgroundColor = [UIColor redColor].CGColor; button.layer.masksToBounds = NO; button.layer.cornerRadius = 10.0f; view.layer.shadowOpacity = 0.5f; view.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:_button.bounds cornerRadius:10.0f].CGPath; view.layer.shadowOffset = CGSizeMake(0.0f, 4.0f); view.layer.shadowRadius = 2.0f; view.layer.masksToBounds = NO; view.layer.cornerRadius = 10.0f; [view addSubview:button]; 
+14
Mar 23 '13 at 23:54
source share

This is the version of Swift 3 and the IBDesignable response sent by @TheSquad.

I used the same concept by making changes to the storyboard file. First, I moved my targetView (one that requires an angular radius and shadow) inside the new container container . Then, I added the following lines of code (Reference: https://stackoverflow.com/a/165267/ ) to add some IBDesignable attributes for the UIView class:

 @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 } } /* The corner radius of the view. */ @IBInspectable var cornerRadius: CGFloat { set { layer.cornerRadius = newValue } get { return layer.cornerRadius } } 

After adding this code, I returned to the storyboard and, having selected my container view , I can now find a new set of attributes in the attribute inspector:

enter image description here

Besides adding values ​​for these attributes of my choice, I also added a corner radius to my targetView and set the masksToBounds property to true.

Hope this helps :)

+2
Aug 05 '17 at 17:17
source share

I also had sharp performance issues with shadows and rounded corners. Instead of using the shadowPath part, I used the following lines that solved performance perfectly:

 self.layer.shouldRasterize = YES; self.layer.rasterizationScale = UIScreen.mainScreen.scale; 
+1
Aug 24 '15 at 21:29
source share

Swift 3.0 with StoryBoard

Same idea with @TheSquad. Create a new view under the actual view and add a shadow to the bottom view.

1. Create a view under the actual view

Drag and drop the UIView into the StoryBoard with the same restriction as your target view. Check the clip to snap to the target view. Also make sure that the new view appears before the target view, so that the target view will cover the new view.

enter image description here

2. Now attach the new view to your code, add a shadow to it

This is just a sample. You can do whatever you want here.

 shadowView.layer.masksToBounds = false shadowView.layer.shadowColor = UIColor.red.cgColor shadowView.layer.shadowOpacity = 0.5 shadowView.layer.shadowOffset = CGSize(width: -1, height: 1) shadowView.layer.shadowRadius = 3 shadowView.layer.shadowPath = UIBezierPath(rect: coverImage.bounds).cgPath shadowView.layer.shouldRasterize = true 
+1
Sep 20 '17 at 20:16
source share

Here is one solution:

  @IBOutlet private weak var blockView: UIView! { didSet { blockView.backgroundColor = UIColor.white blockView.layer.shadowColor = UIColor.black.cgColor blockView.layer.shadowOpacity = 0.5 blockView.layer.shadowOffset = CGSize.zero blockView.layer.cornerRadius = 10 } } @IBOutlet private weak var imageView: UIImageView! { didSet { imageView.layer.cornerRadius = 10 imageView.layer.masksToBounds = true imageView.layer.shouldRasterize = true } } 

enter image description here

0
Nov 28 '17 at 4:53 on
source share



All Articles