You know, I think drop shadows-- they're
like the singletons of the design world.
They're easy to make, but as a result,
they can be overused by people who
don't know what they're doing.
Guilty.
And therefore, it's kind of trendy to make fun of them.
But when done right, drop shadows
can be incredibly useful.
They can be a great way to draw your user's attention
to the usable elements on the screen,
and they can add a nice tactile feel to your app.
And as you also probably noticed,
they play a significant role in Google's material design
guidelines.
So for us, applying shadows in the correct manner
is important.
Not just from a design standpoint,
but from an engineering standpoint as well.
You see, drop shadows can also be expensive.
Do them wrong, and you can waste precious CPU cycles.
But if you do them right, your app
can still look nice while keeping that silky smooth frame
rate.
Let's find out how on this episode of "Route 85."
[MUSIC PLAYING]
So, I want to start by thanking Jeremy Goldberg, a UX
designer working on the Google app for iOS
for providing me with all this great information.
Thanks, Jeremy.
Now, there are many ways to draw shadows on iOS,
each with its own advantages and disadvantages.
But today, we're going to look at two of them.
First up-- drawing shadows in a core animation layer.
Now, this method is great because it's simple.
You just define all your shadow properties
in code, which also means that tweaking or messing with them
later is simply a matter of adjusting a few numbers.
Plus, it's easy to change your shadow dynamically
if that's the kind of thing you're into.
Here, for instance, you can see that I'm
animating the shape of my view and the offset of my shadow,
all in code, and iOS is drawing the shadow appropriately
in real time.
Pretty neat, huh?
Now, you can access the CALayer of any UIView
by accessing its layer property, just like so.
Then adding a shadow is simply a matter
of adding a shadow radius, offset, color, and an opacity.
I'm not going to go into too much detail around these
since you can probably figure them out on your own,
but I do encourage you to play around
with them, if for no other reason than it's kind of fun.
So all this is great, but drawing a shadow in a CALayer
can be slow.
And if you have a lot of elements
onscreen with a lot of shadows, it
can really hurt your performance.
So what can you do?
Well, one tip is to use Bezier paths
to define your shadow's shape.
You see, iOS is calculating the shape of your view
on the fly in order to determine its shadow.
This does let you do really cool things,
like have your UIImageView include
an image with transparency.
IOS will accurately draw the shadow
based on the opaque parts of this image.
Pretty neat, huh?
But this process does require some work.
And if your view is, say, a square,
all this calculation is really unnecessary.
Yeah, you know, iOS, I could have told you
that my view is a square.
In fact, I think I will.
You see, you can explicitly define your shadow's shape
by using a Bezier path.
To do this, first create a CGPath ref to represent
your shadow, and you can do this using any Bezier path drawing
code, but probably drawing a rectangle is a good start.
Then set your path reference as the shadowPath property
of your CALayer.
All your other code can be the same as before.
You've just short-circuited the very expensive step
of having iOS calculate the shape of your shadow.
Incidentally, this also means you
can create a shadow that's not the same shape as your view.
Why would you ever want to do this?
Well, you probably never actually want to do this.
This is weird, but there are some more practical
applications.
For instance, adding a curve shadow
underneath a square image gives it that curved paper look
without your having to actually warp anything in your view.
And you can go with convex here or concave,
and they both look kind of nice.
If you had an oval shadow underneath your view,
you can give it a, hey, my object
is standing up in 3D space over a floor
kind of look, which is cool.
And if you have a complicated shape that would normally
use a complicated shadow-- like, say, this postage stamp image--
you can give it a simple shadow instead, like this rectangle,
and greatly simplify your rendering.
Now, another trick you could try, with caution,
is to rasterize your layer.
Doing so takes a snapshot of your layer,
including its shadow, as a bitmap and caches it.
Which means iOS won't have to recalculate at every frame.
It's really easy to do, just set your CALayers shouldRasterize
property to true, or, yes, depending.
But you need to be careful here.
Rasterizing a layer means your device is doing extra work
copying your layer to memory.
It also means you're using up some
of that precious, precious memory.
And so if the contents of your layer
change on a regular basis, you're
going to be doing more work turning more memory,
and this technique could backfire on you spectacularly.
And I will say that in practice, I
found that Google tends to not use this technique as often
as the Bezier path one.
But if you have a view where the content doesn't change
but the view itself animates-- maybe you
have items in a UICollectionView or you
think a bouncing logo is a good idea for some reason-- those
might be good candidates for rasterization.
Just be sure to use the core animation instrument in Xcode
to confirm that it's giving you the performance boost
that you are expecting.
But if none of these techniques work
for you-- say you've got a really big view with a really
big shadow-- well, then it's time to break out the big guns
and build your shadow as a graphic asset.
See, the theory behind this is that you
create an image to represent your view's shadow
and 9-slice it for easy scaling.
Now, if you're not familiar with the concept
of 9-slicing an image, it basically
means you would take an image like this one
and slice it in a tic-tac-toe pattern, like this.
Now, if you were to resize this image,
those corners would stay unchanged.
But you can see the side sections--
they stretch vertically.
These top and bottom sections will stretch horizontally.
And the center can stretch in both dimensions.
And this allows you to resize your image in such a way
that nothing looks too stretched out or funky.
People often use this technique in creating resizable buttons
or dialog boxes, but it can also be used for shadows.
Neat, huh?
You can see where we're going with this.
Now, there are two ways you can create this image.
One-- create it using a tool like Photoshop, Sketch,
whatever, and export it as a file
and then just import it into your Xcode project.
The other way is you can create a UIImage directly in code.
Turns out this is pretty easy to do since CGContext lets
you draw with a drop shadow.
Either way, you want to end up with a fairly small image that
is ready for 9-slicing.
Now, to 9-slice an image, you're going
to call the UIImage resizable image with cap insets,
and this basically tells iOS where your slices are
for resizing purposes.
Oh, and do make sure that you set your resizing mode
to stretch-- that's important.
Then you just change the frame of your shadow image,
and iOS will resize it based on these cap insets
to scale everything in a nice 9-sliced way.
Add this view as a subview to your content,
iOS scales it, and ta-da, you've got
yourself a nice little shadow.
Now, this technique does have a couple of drawbacks.
One-- it really only works on rectangles, rounded rectangles,
or other shapes that work well with 9-scaling, or 9-slicing.
It doesn't work so well with stars or irregular shapes.
Two-- you have now complicated your view hierarchy
because you've added a new subview everywhere
to represent your shadow, and that can sometimes
get a little messy.
And three-- you've either added more process to your app
if you're generating your shadow using graphics tool,
or more code to your app if you're
drawing your shadow in code which means there are more
places where things can go wrong.
But if you have a lot of large views with large shadows,
and you're smart about reusing this code,
it's probably worth the trade-off.
At least for us, we think it is.
If you look at the Google app on iOS
and look at either the Google Now cards or our recent pages
list, these are all examples of views that have shadows
supplied using images.
So these are just a handful of tricks we use to draw shadows.
Do you have your own?
Feel free to share them in the comments below,
and I'll read them.
Thanks again for watching.
So did you find this useful?
If so, click here to see more videos
from "Route 85," our show for you iOS developers.
And until next time, dear viewers, who knows what evil
lurks in the hearts of men.
The-- actually these days, it's probably the incognito mode
guy.
He's seen some stuff you wouldn't believe.
It's a good thing you can't talk, buddy.
All right, I'll see you all later.
[MUSIC PLAYING]