alengqvist
alengqvist

Reputation: 501

Create shadow around a UIVisualEffectView without covering the whole view

Is it possible to create a shadow around a UIVisualView with UIBlurEffect without letting the UIVisualView get coloured by the shadow underneath?

I basically just want the shadow around the view but with this code the shadow will cover the whole view which darkens the whole view to much:

let borderPath = UIBezierPath(roundedRect: view.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 15, height: 15)).cgPath

shadowView.frame = view.bounds
shadowView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
shadowView.layer.shadowOpacity = 0.3
shadowView.layer.shadowRadius = 3.0
shadowView.backgroundColor = UIColor.clear

shadowView.layer.shadowPath = borderPath
shadowView.layer.shadowOffset = CGSize(width: 0, height: 0)
self.view.insertSubview(shadowView, at: 0)

let blurEffect = UIBlurEffect(style: .extraLight)
let blurView = UIVisualEffectView(effect: blurEffect)
blurView.frame = view.bounds
blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
blurView.clipsToBounds = true
blurView.layer.cornerRadius = 15
view.insertSubview(blurView, aboveSubview: shadowView)

EDIT.
I need to achieve the same thing as in Apple's Maps application. Where the draggable favourite view both uses the UIVisualEffectView and a shadow around its top, without interfering with the UIVisualEffectView's background.

See example screenshots: enter image description here enter image description here

Upvotes: 9

Views: 3653

Answers (5)

kanobius
kanobius

Reputation: 891

I usually solve this kind of situation using composition of views. Instead of setting the shadow in the target view, I create a ShadowView and I put it behind the target view, both views with the same frame.

I've posted and example and code in this question.

An example of the result of this approach is the following:

enter image description here

Upvotes: 0

Ortwin Gentz
Ortwin Gentz

Reputation: 54101

The trick is to not set the shadowPath of the layer. If it is set, the shadow is painted below the visual effect view and, in consequence, darkens the blurred view.

The documentation for shadowPath states:

If you specify a value for this property, the layer creates its shadow using the specified path instead of the layer’s composited alpha channel.

The "instead…" part is what we actually need: the shadow should be composed after rendering the content, based on what the content leaves transparent. Now you might be deterred from not setting a shadowPath because the documentation also states that an "explicit path usually improves rendering performance". However, I didn't see any issues in real life so far. In comparison to the rendering cost of the UIVisualEffectView, painting the shadow doesn't make a difference, I assume.

Also make sure to set the shadow on a superview of the UIVisualEffectView, not on a sibling view.

Upvotes: 1

zgjie
zgjie

Reputation: 2260

I found in iOS 12, this is not a problem, the UIVisualEffectView ignore the shadow of underneath views, it just sees through the shadow, like the shadow not exist.

Upvotes: 2

alengqvist
alengqvist

Reputation: 501

Ok, so the problem was that my background in the underlying view was white. And with the UIBlurEffect .extraLight used on a background which is lighter than the BlurEffect the shadow beneath a UIVisualView appears darker than with a more vivid background.

Also described in this question:
Fix UIVisualEffectView extra light blur being gray on white background

UPDATE

I found a project explaining how to solve this on Github The solution involves creating a 9-part UIImage to represent the shadow. The creator also explains the underlying layers of the iOS 10 Maps.

Upvotes: 5

Liam
Liam

Reputation: 12668

So i'm trying to recreate the look of iOS 10 maps. I decided to attach the maps app in the simulator to the debugger to see what was going on...

View debugger breakdown

Apple actually get around this by having a UIImage over the top of the content with the border and shadow. Not the most elegant way to do it but i'm going for the exact look so I'm going to take the exact approach.

I also grabbed the asset (using this) from the Maps app to save making your own one. Shame they only have @2x artwork in it though :/

CardShadowFull@2x.png

Upvotes: 3

Related Questions