How to Properly Use Backwards Compatible Vector Drawable with the Latest Android Support Library

How to properly use backwards compatible Vector Drawable with the latest Android Support Library?

Add the latest support lib to your app's build.gradle dependencies:

compile 'com.android.support:appcompat-v7:26.0.2'

and add the following line in the same file:

android {
...
defaultConfig {
...
vectorDrawables.useSupportLibrary = true
}
...
}

Import vector image through Vector Asset Studio.

That's all, you are ready to go!


ImageView

XML

Use app:srcCompat attribute instead of android:src:

<ImageView
...
app:srcCompat="@drawable/your_vector"
... />

Programmatically

Directly from resource id:

imageView.setImageResource(R.drawable.your_drawable);

Set as Drawable object (e.g. for tinting):

Drawable vectorDrawable 
= AppCompatResources.getDrawable(context, R.drawable.your_vector);
imageView.setImageDrawable(vectorDrawable);

And if you want to set tint:

DrawableCompat.setTint
(vectorDrawable, ContextCompat.getColor(context, R.color.your_color));

TextView drawable

XML

There is no simple solution: XML attribute android:drawableTop(Bottom etc) can't handle vector images on pre-Lollipop. One solution is to add initializer block to activity and wrap vector into another XML drawable. Second - to define a custom TextView.

Programmatically

Setting resource directly doesn't work, you have to use Drawable object. Get it the same way as for ImageView and set it with the appropriate method:

textView.setCompoundDrawablesWithIntrinsicBounds(vectorDrawable, null, null, null);

Menu icon

There is nothing special:

<item
...
android:icon="@drawable/your_vector"
... />

menuItem.setIcon(R.drawable.your_vector);

Notifications:

It's impossible, you have to use PNGs :(

Android vector compatibility

From Android 5.0 (API level 21) you can use vector drawable in your app. You can use new Android Studio tool called: Vector Asset Studio. It handles PNG making for older versions automatically. See link below for a complete explanation:

Vector Asset Studio

How to use VectorDrawables in Android API lower than 21?

Vector Drawables are now backward compatible, it's just a matter of upgrading your gradle version to 1.4.0-beta3 or higher, and upgrade your IDE :

We are also excited to offer backwards compatibility for your vector
assets in Android Studio 1.4. Once you have a vectorDrawable image in
your res/drawable, the Gradle plugin will automatically generate
raster PNG images for API level 20 and below during build time. This
means you only need to update and maintain your vector asset for your
app project and Android Studio can take care of image conversion
process.

http://android-developers.blogspot.com.uy/2015/09/android-studio-14.html

Android Selector Drawable with VectorDrawables srcCompat

Some things have changed since I asked this question, so I will answer it myself.

With Support Library 23.4.0 the support for VectorDrawables from Ressources was reenabled: Android Support Library 23.4.0 available now

You can find more information on that in this cast from the Google I/O 2016:
What's new in the support library - Google I/O 2016

You need to add this to every Activity where you want to use VectorDrawables on devices below Android 5.0 (Codename Lollipop, API level 21):

static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

So you can now use VectorDrawables in DrawableContainers but it can still cause some issues as mentioned in the sources above so use it with caution.

I did not reenable this feature in my app so far but I will change a lot of my icons to VectorDrawables with my next major release and will then dive deeper into this topic.

Why do API 19 devices (and other devices below API 21) need vectorDrawables.useSupportLibrary to load icons?

The reason for this is that native (as in, built into the Android framework) support for vector drawables was added in API 21 (Android 5.0 Lollipop).

The vectorDrawables.useSupportLibrary option enables a backward-compatibility feature in the Android support library (now known as AndroidX AppCompat) that allows it to load vector drawables at Runtime via the VectorDrawableCompat and AnimatedVectorDrawableCompat classes.

It is also possible to configure the Android Gradle Plugin to convert the vector images to PNG files at build time for use on pre–API 21 devices, but this defeats many of the benefits of using vector drawables in the first place, such as smaller app size.

How can I use vectorDrawable as icon for push notifications using Android Support Library 23.2? setSmallIcon gives error

No, VectorDrawables can only be sent outside your app on Android 5.0+ devices - the framework does not know how to handle vector drawables prior to that.

VectorDrawable - is it available somehow for pre-Lollipop versions of Android?

UPDATE ON March 2016

By Android Support Library 23.2.1 update, Support Vector Drawables and Animated Vector Drawables. (you can also use latestone for the same)

Please update version of a library in gradle file.

compile 'com.android.support:recyclerview-v7:23.2.1'

Vector drawables allow you to replace multiple png assets with a single vector graphic, defined in XML. While previously limited to Lollipop and higher devices, both VectorDrawable and AnimatedVectorDrawable are now available through two new Support Libraries support-vector-drawable and animated-vector-drawable. new app:srcCompat attribute to reference vector drawables .

Check source on github with some sample examples.

Changes for v7 appcompat library:

Reverted dependency on vector assets so that developers using the appcompat library are not forced to use VectorDrawable and its associated build flags.

Is it possible to use VectorDrawable in Buttons and TextViews using android:DrawableRight?

it possible to use drawableRight etc for SVG assets ?

Yes

AppCompatTextView now supports app:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompat and app:drawableEndCompat compound drawables, supporting backported drawable types such as VectorDrawableCompat.

Include this in your gradle file

implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'

In your text view you can use

app:drawableLeftCompat
app:drawableStartCompat

If you have problems while using app:drawableLeftCompat, app:drawableStartCompat in buttons you will need to update your library to

androidx.appcompat:appcompat:1.2.0-alpha01

they had a bug on

androidx.appcompat:appcompat:1.1.0-alpha01

you can see the docs


Or if you don't want to update yet, then:

Because it seems Google not going to do anything about this issue any time soon, I had to came up with a more solid reusable solution for all of my apps:

  1. First add custom TextView attributes in attrs.xml file of your app "res/values/attrs.xml" :

    <resources>
    <declare-styleable name="CustomTextView">
    <attr name="drawableStartCompat" format="reference"/>
    <attr name="drawableEndCompat" format="reference"/>
    <attr name="drawableTopCompat" format="reference"/>
    <attr name="drawableBottomCompat" format="reference"/>
    </declare-styleable>
    </resources>
  2. Then create custom TextView class like this:

    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.drawable.Drawable;
    import android.os.Build;
    import android.support.v7.content.res.AppCompatResources;
    import android.support.v7.widget.AppCompatTextView;
    import android.util.AttributeSet;

    public class CustomTextView extends AppCompatTextView {
    public CustomTextView(Context context) {
    super(context);
    }
    public CustomTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initAttrs(context, attrs);
    }
    public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initAttrs(context, attrs);
    }

    void initAttrs(Context context, AttributeSet attrs) {
    if (attrs != null) {
    TypedArray attributeArray = context.obtainStyledAttributes(
    attrs,
    R.styleable.CustomTextView);

    Drawable drawableStart = null;
    Drawable drawableEnd = null;
    Drawable drawableBottom = null;
    Drawable drawableTop = null;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    drawableStart = attributeArray.getDrawable(R.styleable.CustomTextView_drawableStartCompat);
    drawableEnd = attributeArray.getDrawable(R.styleable.CustomTextView_drawableEndCompat);
    drawableBottom = attributeArray.getDrawable(R.styleable.CustomTextView_drawableBottomCompat);
    drawableTop = attributeArray.getDrawable(R.styleable.CustomTextView_drawableTopCompat);
    } else {
    final int drawableStartId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableStartCompat, -1);
    final int drawableEndId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableEndCompat, -1);
    final int drawableBottomId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableBottomCompat, -1);
    final int drawableTopId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableTopCompat, -1);

    if (drawableStartId != -1)
    drawableStart = AppCompatResources.getDrawable(context, drawableStartId);
    if (drawableEndId != -1)
    drawableEnd = AppCompatResources.getDrawable(context, drawableEndId);
    if (drawableBottomId != -1)
    drawableBottom = AppCompatResources.getDrawable(context, drawableBottomId);
    if (drawableTopId != -1)
    drawableTop = AppCompatResources.getDrawable(context, drawableTopId);
    }

    // to support rtl
    setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStart, drawableTop, drawableEnd, drawableBottom);
    attributeArray.recycle();
    }
    }
    }
  3. Now you can use it easily in any layouts by your custom attributes:

    <YOUR_VIEW_PACKAGE.CustomTextView
    android:id="@+id/edt_my_edit_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:drawableStartCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
    app:drawableEndCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
    app:drawableTopCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
    app:drawableBottomCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
    />
    • You can do similar thing with Button, EditText and RadioButton because they derived from TextView

Hope this helps :)



Related Topics



Leave a reply



Submit