I have to create a custom UIView
that will have round corners, a border, a shadow and its drawRect()
method is overridden to provide custom drawing code with which several straight lines are drawn into the view (I need to use a fast, lightweight approach here since many of these views may be rendered).
The problem I'm currently facing is that the shadow doesn't apply anymore to the round corners as soon as I override drawRect()
in the view class (even without any custom code yet in it). See the attached image for the difference:
In the view controller I'm using the following code:
view.layer.cornerRadius = 10;
view.layer.masksToBounds = true;
view.layer.borderColor = UIColor.grayColor().CGColor;
view.layer.borderWidth = 0.5;
view.layer.contentsScale = UIScreen.mainScreen().scale;
view.layer.shadowColor = UIColor.blackColor().CGColor;
view.layer.shadowOffset = CGSizeZero;
view.layer.shadowRadius = 5.0;
view.layer.shadowOpacity = 0.5;
view.layer.masksToBounds = false;
view.clipsToBounds = false;
In the overridden drawContext()
I would use something like:
var context:CGContext = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, UIColor.redColor().CGColor);
// Draw them with a 2.0 stroke width so they are a bit more visible.
CGContextSetLineWidth(context, 2.0);
CGContextMoveToPoint(context, 0.0, 0.0); //start at this point
CGContextAddLineToPoint(context, 20.0, 20.0); //draw to this point
CGContextStrokePath(context);
But as said above, the shadow problem occurs even without this code added.
Is there any other/better way to draw lightweight elements onto a view other than this approach that is compatible with round corners and shadows? I don't want to add any unnecessary extra views or image contexts to the view since these need to be light and performant.
This is a tricky one.
UIView
'sclipsToBounds
is necessary to get the rounded corners. ButCALayer
'smasksToBounds
has to befalse
so the shadow is visible. Somehow, everything works ifdrawRect
is not overridden, but actually it shouldn't.The solution is to create a superview to provide the shadow (in the demonstration below this is the
shadowView
). You can test the following in Playground:Result:
I wrote a small extension to UIView to manage both rounded corners AND drop shadow. As the variables are @IBInspectable, everything can be set directly in the storyboard !
And this is how it looks in the storyboard :
The result :
There is one requirement : DON'T touch either clipToBounds on the view (in code or in IB) or masksToBound on the layer.
NB: one case in which it won't work : tableViews. As UITableView automatically triggers
clipToBounds
under the hood, we can't have a drop shadow.EDIT: as Claudia Fitero aptly noticed, you need to leave a small padding around the view to which you are adding a shadow, otherwise the shadow won't be visible. A 2px-padding is enough generally (depending on your shadow radius).
In Swift 4.1. For making rounded corner of UIView I have created Extension of UIView as follow.
SWIFT 3 Solution
Adapted from Mundi's answer