Draw shadow only from 3 sides of UIView Draw shadow only from 3 sides of UIView ios ios

Draw shadow only from 3 sides of UIView


I know you say setting layer.shadowOffset won't work for you, but you are allowed to put in negative values so setting it layer.shadowOffset = CGSizeMake(0.0, -2.0) would come close to the effect you're looking for but of course I expect you want it to be even on the three sides.

So here we go with layer.shadowPath!

UIView *block1 = [[UIView alloc] initWithFrame:CGRectMake(32.0, 32.0, 128.0, 128.0)];[block1 setBackgroundColor:[UIColor orangeColor]];[self.view addSubview:block1];block1.layer.masksToBounds = NO;block1.layer.shadowOffset = CGSizeMake(0, 0);block1.layer.shadowRadius = 1;block1.layer.shadowOpacity = 0.7;UIBezierPath *path = [UIBezierPath bezierPath];// Start at the Top Left Corner[path moveToPoint:CGPointMake(0.0, 0.0)];// Move to the Top Right Corner[path addLineToPoint:CGPointMake(CGRectGetWidth(block1.frame), 0.0)];// Move to the Bottom Right Corner[path addLineToPoint:CGPointMake(CGRectGetWidth(block1.frame), CGRectGetHeight(block1.frame))];// This is the extra point in the middle :) Its the secret sauce.[path addLineToPoint:CGPointMake(CGRectGetWidth(block1.frame) / 2.0, CGRectGetHeight(block1.frame) / 2.0)];// Move to the Bottom Left Corner[path addLineToPoint:CGPointMake(0.0, CGRectGetHeight(block1.frame))];// Move to the Close the Path[path closePath];block1.layer.shadowPath = path.CGPath;

And to give you an idea of whats going on, here is the actual shadow path you just drew :)

enter image description here

Its possible to just shift that extra middle point before or after the other lines to choose which side will be omitted.


A bit of improvement for other answers, thanks to Ashok R for swift code.

Since we were creating a triangular view in the background of the view with shadow on all sides, and a white triangle on the sides shadow is not needed.

It breaks in case of views with width comparatively larger than height.

image with triangle shadow

A workaround will be to shift the path for the line where shadow is not needed a bit towards that side of view, instead of creating the triangular view Path completely.

I have created an extension for that -

extension UIView {    func addshadow(top: Bool,                   left: Bool,                   bottom: Bool,                   right: Bool,                   shadowRadius: CGFloat = 2.0) {        self.layer.masksToBounds = false        self.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)        self.layer.shadowRadius = shadowRadius        self.layer.shadowOpacity = 1.0        let path = UIBezierPath()        var x: CGFloat = 0        var y: CGFloat = 0        var viewWidth = self.frame.width        var viewHeight = self.frame.height        // here x, y, viewWidth, and viewHeight can be changed in        // order to play around with the shadow paths.        if (!top) {            y+=(shadowRadius+1)        }        if (!bottom) {            viewHeight-=(shadowRadius+1)        }        if (!left) {            x+=(shadowRadius+1)        }        if (!right) {            viewWidth-=(shadowRadius+1)        }        // selecting top most point        path.move(to: CGPoint(x: x, y: y))        // Move to the Bottom Left Corner, this will cover left edges        /*         |☐         */        path.addLine(to: CGPoint(x: x, y: viewHeight))        // Move to the Bottom Right Corner, this will cover bottom edge        /*         ☐         -         */        path.addLine(to: CGPoint(x: viewWidth, y: viewHeight))        // Move to the Top Right Corner, this will cover right edge        /*         ☐|         */        path.addLine(to: CGPoint(x: viewWidth, y: y))        // Move back to the initial point, this will cover the top edge        /*         _         ☐         */                path.close()        self.layer.shadowPath = path.cgPath    }

and set the boolean true for whichever side you want the shadow to appear

myView.addshadow(top: false, left: true, bottom: true, right: true, shadowRadius: 2.0)

// shadow radius is optional above and is set as default at 2.0

enter image description here

or myView.addshadow(top: true, left: true, bottom: true, right: true, shadowRadius: 2.0)

enter image description here

or myView.addshadow(top: false, left: false, bottom: true, right: true, shadowRadius: 2.0)

enter image description here


Updating Ryan Poolos Answer to Swift 3.0

Thanks to Ryan Poolos

class sampleViewController: UIViewController {    var block1: UIView! = nil    override func viewDidLoad() {        super.viewDidLoad()        block1 = UIView(frame: CGRect(x: 32.0, y: 32.0, width: 128.0, height: 128.0))        block1.backgroundColor = UIColor.orange        self.view.addSubview(block1)        block1.layer.masksToBounds = false        block1.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)        block1.layer.shadowRadius = 1.0        block1.layer.shadowOpacity = 0.7        let path = UIBezierPath()        // Start at the Top Left Corner        path.move(to: CGPoint(x: 0.0, y: 0.0))        // Move to the Top Right Corner        path.addLine(to: CGPoint(x: block1.frame.size.width, y: 0.0))        // Move to the Bottom Right Corner        path.addLine(to: CGPoint(x: block1.frame.size.width, y: block1.frame.size.height))        // This is the extra point in the middle :) Its the secret sauce.        path.addLine(to: CGPoint(x: block1.frame.size.width/2.0, y: block1.frame.size.height/2.0))        // Move to the Bottom Left Corner        path.addLine(to: CGPoint(x: 0.0, y: block1.frame.size.height))        path.close()        block1.layer.shadowPath = path.cgPath    }}

Result:

image