Animation / Drawable / VectorDrawable

Vectors For All (finally)

This is the third post in an occasional series looking at the state of VectorDrawable support for Android. The previous articles are Vectors For All (almost) which was followed by Vectors For All (slight return). While these posts show that there has been a big improvement in the VectorDrawable tools available to us, but the eagerly awaited VectorDrawableCompat was still missing. Until now. On 24th February 2016 Google released Android Support Library 23.2 which, among other things contains the eagerly anticipated VectorDrawableCompat.

I’m not going to give a lengthy howto of the ins and outs of using VectorDrawableCompat because Chris Banes has already done that in a fairly in-depth blog post. Chris has already done an excellent job of explaining how to use VectorDrawableCompat so it would serve little useful purpose to simply repeat that here.

So let’s take a look at the changes that we need to make to the project that we’ve used in the previous articles in order to use VectorDrawableCompat. The first thing that we need to do is make the modifications to our build.gradle file that Chris explains in his post.

For the sample code I’m using Android Gradle plugin 1.5.0 and not the newer 2.0.0 beta one. The reason for this is that the beta plugin has built in expiry, and I prefer to publish sample code that should compile in weeks and months time – I’ll happily move to 2.0.0 once a stable version is released. That said, we need to make the following changes (it’s different for 2.0.0 – see Chris’ post for details – but I’ve tested that method as well and it works perfectly):

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.stylingandroid.vectors4all"
        minSdkVersion 7
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        generatedDensities = []
    }
    aaptOptions {
        additionalParameters "--no-version-vectors"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.0'
}

apply from: '../config/static_analysis.gradle'

What this does it essentially turn off the auto-generation of PNG assets from our VectorDrawable ones which was a previous way of doing things.

The next thing that we need to do is switch to app:srcCompat instead of android:src for the ImageView in our layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  tools:context=".MainActivity">

  <ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="@null"
    app:srcCompat="@drawable/svg_logo2" />

</RelativeLayout>

That’s all there is to it! Our Activity already extends AppCompatActivity which is the other prerequisite.

the only minor niggle here is that Android Studio (I’m using 2.0 beta 6 at the time of writing) doesn’t recognise the app:srcCompat attribute and so gives an error. But everything compiles correctly. We also get a few false lint warnings but these can be suppressed, if necessary. I expect these false errors & warnings will be fixed fairly soon.

So if we run that on a Marshmallow device all looks good, as we’d expect:

compat-m

And if we run it on a Jelly Bean emulator it looks pretty much identical:

compat-jb

So what about AnimatedVectorDrawableCompat? Let’s re-visit the samples from the Styling Android series on VectorDrawable to see how they work.

We modify the project in much the same way as we did before – one difference is that we need to change our Activity to extend AppCompatActivity this time. So let’s step through our examples:

First there is the static Android logo:

screenshot-2016-02-27_11.03.32.637

As this is a static VectorDrawable we’d expect it to work, and it looks great. What happens when we animate it (these examples are all from a GenyMotion JellyBean emulator):

The frame-rate is pretty good – and this is on an emulator rather than a real device! Obviously frame-rates will be worse on lower powered devices, and we’re likely to encounter many more of them when targeting earlier versions of Android, but the results are pretty impressive, nonetheless.

So how about the trimPath animation?:

Once again, this is pretty impressive – it works as it should and is very smooth.

The final example from the previous series does not work, sadly. This is because it directly animates pathData and, as Chris mentions, this is not currently supported by AnimatedVectorDrawableCompat. However Chris does use the word “currently” – so perhaps a future version of the library will support this extremely powerful feature.

So that’s it for the Compat library – it really does perform well and is pretty easy to integrate in to your current app. A massive hat tip to Chris and the rest of the team who have worked on bringing this functionality to the masses.

So, let’s now turn our attention to the other aspect of using vectors in our apps – actually converting SVG assets in to VectorDrawable. Previously we saw how there were some omissions in the SVG support which meant that we were unable to import the official SVG logo (which should be considered a benchmark for basic SVG support) using both Android Studio import and the third party SVG to VectorDrawable tool. There’s good news and there’s bad news.

First the bad news: Sadly Android Studio still does not import the logo without errors – I’ve tested on Android Studio 2.0 beta 6, and it’s still not supported.

However the good news is that shortly after I published the last article in this series I was contacted by Juraj Novák (the creator of the third party tool) to say that the missing missing support for local IRI references (see my earlier articles for a explanation of this) had been added. There is one small caveat: You must select the “Bake transforms into path (experimental)” option when converting the SVG logo asset but, provided you do, it is converted faithfully in to a VectorDrawable xml which you can drop in to your project.

There is still no support for SVG gradients and patterns, but this is because they are not supported in VectorDrawable itself – only SVG path data is actually supported.

With Juraj’s conversion tool, and the new VectorDrawableCompat library this stuff really now is ready for the mainstream. So get out there and Vector, people!

There is updated code supporting the Compat library for both the previous Vectors For All posts and VectorDrawable.

© 2016, Mark Allison. All rights reserved.

Copyright © 2016 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

7 Comments

  1. Hi Mark,

    Another interesting article. However, the described scenario doesn’t seem to work entirely as described for me, running Android Studio 1.5.1 with Build Tools 23.0.3 and Gradle 2.8. My build includes the com.android.support:appcompat-v7:23.2.1 library, but the “app:srcCompat” attribute is not supported, i.e. results in compile-time failures. I also have problems with the “vectorDrawables.useSupportLibrary = true” in build.gradle (for Module: app) not being recognized.

    On the other hand, I can – at least in theory – directly import vector graphics through the Vector Asset Studio. The latter, however, only works well with the material icons, and hasn’t, to date, been able to read any of the SVGs I’ve prepared. All the same, using Juraj Novák’s SVG2Android tool I’m able to convert my SVGs to VectorDrawables that Android Studio, my emulators and phone are willing to accept.

    Two problems remain, however: 1) tons of PNGs are being generated for each of the VectorDrawables included (which of course means that these graphics are not scalable in the earliest supported SDK for my application – i.e. API 15); and 2) somewhat more complicated SVGs need a lot of editing and trial-and-error to result in relatively simply VectorDrawables. The latter is needed since my phone otherwise crashes on these files. This, in itself, is quite strange, though, as my Samsung Galaxy S5 is relatively new (6 months about) and the same graphics that make the phone crash work fine in Android Studio’s UI-preview and on the two emulators (API 23 and API 15) I use. Any idea how I might resolve these issues?

    Thanks in advance!

    All the best,
    Alexander.

  2. Hi Mark,

    Another great article! Unfortunately, things seem to work a little differently for me, however.

    My set-up is as follows:
    Android Studio 1.5.1
    Gradle 2.8
    Build Tools 23.0.3
    com.android.support:appcompat-v7:23.2.1

    With this set-up I do not have availability of the “app:srcCompat”-attribute (using it results in a compile time failure), but can, instead, use the regular “android:src”-attribute. I also cannot use the “vectorDrawables.useSupportLibrary = true” directive in my app’s build.gradle, resulting in numerous PNGs being generated for each imported VectorDrawable.

    Although I’m offered the Vector Asset Studio to import local SVGs, the Vector Assset Studio only works well for the standard material icons, and hasn’t, to date, worked for any of my SVGs. Conversion of SVGs to VectorDrawables works fine when using Juraj Novák’s Android SVG to VectorDrawable-tool, however, and this is how I now include SVGs in my project. Some of the SVGs need to be significantly simplified, however, as the somewhat more complex ones might display in Android Studio and on the emulators, but make my 6-months-old Samsung Galaxy S5 crash.

    Any idea how I could prevent all the PNGs from being generated and instead use VectorDrawableCompat on older APIs (up to 15) to minimize my App’s size? And is there any way to get the Vector Asset Studio to work properly?

    Thanks for your help!

    All the best,
    Alexander.

    1. Try reading Chris Banes’ article which gives full details of how to get this working https://chris.banes.me/2016/02/25/appcompat-vector/. It looks like you have followed the instructions for gradle plugin 2.x and not 1.5.x which you are using – you need to add build config options to turn off auto-generation of PNGs.

      Try reading my article. I clearly state “First the bad news: Sadly Android Studio still does not import the logo without errors – I’ve tested on Android Studio 2.0 beta 6, and it’s still not supported.”. Therefore SVG import with Android Studio does not work well. That’s why I advocate the use of a third party solution over Android Studio.

      1. Hi Mark,

        I read Chris Banes’ article as well, but was under the impression that I had to follow the instructions for the 2.x gradle plugin, seeing as Android Studio project properties report my using Gradle 2.8. I’m sorry if I’m indeed confusing things here, but I’m rather new to Android development and find the whole experience to be rather something of a mess compared to the more professional environments I’m used to… I’ll give the 1.5.x method a try, though, just to exclude this being the deal-breaker.

        Overall I’m growing a bit sceptical about using vector graphics in my App, however, as the emulators might be able to display those I’m using properly, but they may still make my phone crash without any apparent reason. This makes me wonder whether I could reliably use vector graphics on all devices I’d want to support, or whether it might not just be better to stick with PNG… Add to this that I’ve read some strange articles concerning device localization settings affecting vector rendering and the fact that I’ve got some more complex vector graphics to include (which make my App crash on both emulator and phone, but not in render preview) and I’m even less sure whether vector graphics is a good idea…

        On the whole, though, I agree that the third party tool is an excellent way to convert SVG to VectorDrawable. It’s just that support for VectorDrawable seems rather quirky still…

        In any case, thanks for your help!

        Cheers,
        Alexander.

        1. It’s not the version of gradle that’s important, it’s the version of the android gradle plugin which is important. They are two different things. You specify this in your build.gradle:

          buildscript {
          repositories {
          jcenter()
          }
          dependencies {
          classpath 'com.android.tools.build:gradle:1.5.0'
          }
          }

          The above example shows that 1.5.0 is being used.

          1. Hi Mark,

            Indeed, you were right about the version of Gradle plug-in. A good thing to know! Anyway, between the above configuration, the “app:srcCompat”-attribute and the 3rd-party tool for converting SVG to VectorDrawable, I now seem to have full vector graphics support in my App. Moreover, I no longer seem to be suffering from my former problems with the rendering of more complex vector graphics! It even works perfectly on my old Samsung with Gingerbread 2.3.3 API 10! So thanks for your help in this! It will really save me a lot of work!

            One thing I did notice, however, which I’m not sure you mentioned before, is that – at least on my Samsung Galaxy S5 – blowing up a vector graphic (i.e. scaling it up from e.g. 50 x 50 dp to 400 x 400 dp) will result in a badly anti-aliased image, just as if we had scaled a raster image up from a lower to a higher resolution. Importing your vector graphic at a higher dp resolution seems to solve this, however. Also, the reason why I got a build error on the “app:srcCompat”-attribute earlier is most likely that the namespace wasn’t defined. I’ve since used {xmlns:app=”http://schemas.android.com/apk/res-auto”}. This results in an error in the XML, but the project itself builds and runs fine.

            Anyway, thanks again! I’m now good to go, and can finally easily import my graphics!

            Cheers,
            Alexander.