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 :)
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.
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
or myView.addshadow(top: true, left: true, bottom: true, right: true, shadowRadius: 2.0)
or myView.addshadow(top: false, left: false, bottom: true, right: true, shadowRadius: 2.0)
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: