How to Use Vectordrawable in Buttons and Textviews Using Android:Drawableright

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 :)

DrawableLeft with xml icon

Best way I've found:

static public void setLeftDrawable(View view, Context c, int drawable) {
Drawable leftDrawable = AppCompatResources.getDrawable(c, drawable);

if (view instanceof TextInputEditText) {
((TextInputEditText) view).setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);

} else if (view instanceof BootstrapEditText) {
((BootstrapEditText) view).setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);

} else if (view instanceof EditText) {
((EditText) view).setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);

} else if (view instanceof TextView) {
((TextView) view).setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
}
}

Then just call passing the View, the Context and the Drawable, very easy!

Unable to add drawable start with SVG to TextView for Android API lowers that 21

Add vectorDrawables.useSupportLibrary = true in you app level build.gradle as follows:

  //For Gradle Plugin 2.0+
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}

Refer to this guide.

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 :(

How to programmatically set drawableLeft on Android button?

You can use the setCompoundDrawables method to do this. See the example here. I used this without using the setBounds and it worked. You can try either way.

UPDATE: Copying the code here incase the link goes down

Drawable img = getContext().getResources().getDrawable(R.drawable.smiley);
img.setBounds(0, 0, 60, 60);
txtVw.setCompoundDrawables(img, null, null, null);

or

Drawable img = getContext().getResources().getDrawable(R.drawable.smiley);
txtVw.setCompoundDrawablesWithIntrinsicBounds(img, null, null, null);

or

txtVw.setCompoundDrawablesWithIntrinsicBounds(R.drawable.smiley, 0, 0, 0);

Using android vector Drawables on pre Lollipop crash

LATEST UPDATE - Jun/2019

Support Library has changed a bit since the original answer. Now, even the Android plugin for Gradle is able to automatically generate the PNG at build time. So, below are two new approaches that should work these days. You can find more info here:

PNG Generation

Gradle can automatically create PNG images from your assets at build time. However, in this approach, not all xml elements are supported. This solution is convenient because you don't need to change anything in your code or in your build.gradle. Just make sure you are using Android Plugin 1.5.0 or higher and Android Studio 2.2 or higher.

I'm using this solution in my app and works fine. No additional build.gradle flag necessary. No hacks is necessary. If you go to /build/generated/res/pngs/... you can see all generated PNGs.

So, if you have some simple icon (since not all xml elements are supported), this solution may work for you. Just update your Android Studio and your Android plugin for Gradle.

Support Library

Probably, this is the solution that will work for you. If you came here, it means your Android Studio is not generating the PNGs automatically. So, your app is crashing.

Or maybe, you don't want Android Studio to generate any PNG at all.

Differently from that "Auto-PNG generation" which supports a subset of XML element, this solution, supports all xml tags. So, you have full support to your vector drawable.

You must first, update your build.gradle to support it:

android {
defaultConfig {
// This flag will also prevents Android Studio from generating PNGs automatically
vectorDrawables.useSupportLibrary = true
}
}

dependencies {
// Use this for Support Library
implementation 'com.android.support:appcompat-v7:23.2.0' // OR HIGHER

// Use this for AndroidX
implementation 'androidx.appcompat:appcompat:1.1.0' // OR HIGHER
}

And then, use app:srcCompat instead of android:src while loading VectorDrawables. Don't forget this.

For TextView, if you are using the androidx version of the Support Library, you can use app:drawableLeftCompat (or right, top, bottom) instead of app:drawableLeft

In case of CheckBox/RadioButton, use app:buttonCompat instead of android:button.

If you are not using the androidx version of the Support Library and your minSdkVersion is 17 or higher or using a button, you may try to set programmatically via

Drawable icon = AppCompatResources.getDrawable(context, <drawable_id>);
textView.setCompoundDrawablesWithIntrinsicBounds(<leftIcon>,<topIcon>,<rightIcon>,<bottomIcon>);

UPDATE - Jul/2016

They re-enabled that VectorDrawable in

Android Support Library 23.4.0

For AppCompat users, we’ve added an opt-in API to re-enable support Vector Drawables from resources (the behavior found in 23.2) via AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) - keep in mind that this still can cause issues with memory usage and problems updating Configuration instances, hence why it is disabled by default.

Maybe, build.gradle setting is now obsolete and you just need to enable it in proper activities (however, need to test).

Now, to enable it, you must do:

public class MainActivity extends AppCompatActivity {
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

...
}

Original Answer - Apr/2016

I think this is happening because Support Vector was disabled in the latest library version: 23.3.0

According to this POST:

For AppCompat users, we’ve decided to remove the functionality which let you use vector drawables from resources on pre-Lollipop devices due to issues found in the implementation in version 23.2.0/23.2.1 (ISSUE 205236). Using app:srcCompat and setImageResource() continues to work.

If you visit issue ISSUE 205236, it seems that they will enable in the future but the memory issue will not be fixed soon:

In the next release I've added an opt-in API where you can re-enable the VectorDrawable support which was removed. It comes with the same caveats as before though (memory usage and problems with Configuration updating).

I had a similar issue. So, in my case, I reverted all icons which use vector drawable from resource to PNG images again (since the memory issue will keep happening even after they provide an option to enable it again).

I'm not sure if this is the best option, but it fixes all the crashes in my opinion.

VectorDrawable not showing or drawed wrong

VectorDrawable added in API level 21.

Support Library 23.2 or higher provides full support to Vector
Drawables and Animated Vector Drawables on devices running Android 5.0
(API level 21) or lower.

You should use

 app:srcCompat="@drawable/your_vector_image"

You need to add vectorDrawables.useSupportLibrary = true to your build.gradle file:

// Gradle Plugin 2.0+  
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}

FYI

app:srcCompat attribute to reference vector drawables as well as any
other drawable available to android:src.



Related Topics



Leave a reply



Submit