VectorDrawable Adaptive Icons
So the Android O APIs are final — API 26 is here! That means you can start compiling with API 26 right now (and you should really always compile with the latest SDK) as well as work towards targeting API 26.
One of the first things you should consider working on is providing an adaptive icon — an icon made of a separate background and foreground layer. This new format provides a consistent shape across all icons on a device and will also allow launchers to add visual effects by animating the background and foreground separately. This is really how you make a good first impression for users with Android O devices.
With the system handling the outer edge shape and its shadow, adaptive icons give you a chance to re-evaluate how you build your app icon. If you’re able to build your app icon as an SVG/vector image, consider avoiding bloating your app with more PNGs for the background and foreground and take advantage of VectorDrawables for your adaptive icon.
Note: there are valid cases where PNGs are the correct choice for your app. Talk to your designer before trying to force everything into vector drawables.
I’ll walk you through what it took to convert Muzei’s current icon into an adaptive icon.
Note: you do not need to target API 26 to provide an adaptive icon — only compile against it. Users will benefit from your work even as you work through other behavior changes.
The basics of adaptive icons
Let’s assume your Android Manifest’s
<application> tag has
android:icon="@mipmap/ic_launcher". To add an adaptive icon that replaces those PNGs on API 26+ devices, you’ll add a
res/mipmap-anydpi-v26/ic_launcher.xml file that looks like this:
By placing it in the
mipmap-anydpi-v26 folder, the resource system will use it in preference over any files in the other
dpi folders (exactly what you want, since this file is replacing all of them) and that it should only be used in API 26+ devices.
You’ll notice that the drawables are in the
drawable directory. This is because I’m using vector drawables. If you are using PNGs, this should most definitely be in
mipmap. Another option is use a color resource for your background:
For those of you with an
android:roundIcon, you must keep that attribute to continue to support API 25 devices. Devices with round masks will use your custom
roundIcon if available, but it is strongly suggested to use a single adaptive icon for those devices as well (this ensures you get the standard shadow, support for visual effects, etc).
I find this easiest by creating an alias resource. You’d keep your
ic_launcher_round images in the
res/mipmap directories for API 25 devices, but add a file in your
Building a VectorDrawable Background
The background is a great place to start. Being a full bleed 108 x 108 dp image, there’s not much special about this one:
<!-- Your background vector -->
Just keep in mind that due to the masking of the image, users will usually only see the middle 72 x 72 dp.
Building a VectorDrawable Foreground
The foreground image, on the other hand, offers a unique challenge.
First, you have to handle creating the foreground shape itself. It is still on the same 108 x 108 dp artboard, but the ‘safe zone’ of what you know will be shown is only a middle circle of radius 33 dp — don’t put anything critical outside of that part!
Where I initially got stuck was when it comes to the traditional 45º material cast shadow that the foreground also needs to include. Normally, this would be where you’d have to break out the PNGs to get that perfect gradient. But gradient support was added to VectorDrawables back to API 24!
Now, Roman Nurik, the maker of the original Muzei icon, had made a fantastic SVG version of the launcher icon including the shadow as a
<linearGradient> element in the SVG. I won’t pretend that I know how he came up with the correct values — talk to your local designers or read the material design guidelines for product icons a couple hundred times.
But what it became was a
res/color/ic_launcher_shadow.xml file that looks like this:
Note: As of Android Studio 3.0 Canary 3, Android Studio flags
gradientas an error (‘Element gradient must be declared’). It still works.
Now, we can refer to our gradient color the same way you’d refer to a color: with
@color/ic_launcher_shadow in the
VectorDrawable. In Muzei’s case, this means that the foreground background consists of two paths: the shadow and then the shape below it:
android:pathData="<your shadow's path>"/>
<!-- This is your shape drawn on top of your shadow -->
Note: this is also how you’d add a finish layer to your icon — a separate gradient above your shape as explained in the material design guidelines.
All the benefits, none of the APK bloat
By taking advantage of API 24’s addition of gradients to VectorDrawables, we can build well designed VectorDrawable adaptive icons that have the correct material shadows on foreground elements without resorting to adding even more PNGs into the app.
If you want to see it in action, join Muzei’s open beta, then download Muzei on an Android O Dev Preview 3 device and check out the commit that added the adaptive icon. (Although unless you have the superhuman ability to visualize VectorDrawables like Nick Butcher, you might find the full commit doesn’t add much over the code we already covered.)
For further information, you might want to check out Nick Butcher’s excellent series of articles on adaptive icons.
Android O introduces an new application icon format called adaptive icons, intended to make all icons on a device more…medium.com
App Shortcut Adaptive Icons
As mentioned in the adaptive icon page, you should also convert your App Shortcuts to use adaptive icons. The same rules apply here: create a new v26 directory and split your shortcut into a background and foreground (see Muzei’s commit that does exactly that).
If you’re building a dynamic shortcut using a Bitmap, you might find the Support Library 26.0.0-beta2’s
IconCompat.createWithAdaptiveBitmap() useful in ensuring that your Bitmap is masked correctly to match other adaptive icons.