Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have a selector of vector drawables?

Background

I've made the following ImageView, to support selectors as "src" :

public class CheckableImageView extends ImageView implements Checkable {
    private boolean mChecked;

    private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };

    public CheckableImageView(final Context context, final AttributeSet attrs) {
        super(context, attrs);
        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.com_app_CheckableImageView, 0, 0);
        setChecked(a.getBoolean(R.styleable.com_app_CheckableImageView_com_app_checked, false));
        a.recycle();
    }

    @Override
    public int[] onCreateDrawableState(final int extraSpace) {
        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
        if (isChecked())
            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
        return drawableState;
    }

    @Override
    public void toggle() {
        setChecked(!mChecked);
    }

    @Override
    public boolean isChecked() {
        return mChecked;
    }

    public interface OnCheckStateListener {
        void onCheckStateChanged(boolean checked);
    }

    private OnCheckStateListener mOnCheckStateListener;

    public void setOnCheckStateListener(OnCheckStateListener onCheckStateListener) {
        mOnCheckStateListener = onCheckStateListener;
    }

    @Override
    public void setChecked(final boolean checked) {
        if (mChecked == checked)
            return;
        mChecked = checked;
        refreshDrawableState();
        if (mOnCheckStateListener != null) 
            mOnCheckStateListener.onCheckStateChanged(checked);
    }
}

The problem

The above code works fine with normal selectors, that have image files as items drawable for each state.

Thing is, it doesn't work at all with vector drawables (using "srcCompat"). Instead, it shows an empty content.

Here's what I tried:

        <...CheckableImageView
         ...
            app:srcCompat="@drawable/selector"/>

And the selector (for example) is :

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item  android:state_checked="true" android:drawable="@drawable/test"/>
    <item  android:state_pressed="true" android:drawable="@drawable/test" />
    <item android:drawable="@drawable/test2" />
</selector>

example vector drawable:

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="48"
        android:viewportHeight="48">

    <path
        android:fillColor="#0000ff"
        android:strokeColor="#000000"
        android:pathData="M 0 0 H 48 V 48 H 0 V 0 Z" />

    <path
        android:fillColor="#ff0000"
        android:strokeColor="#000000"
        android:pathData="M14.769224,32.692291l5.707315,-17.692275l3.073244,17.479182l6.585245,-16.413424l2.634209,16.200186l-4.170761,-8.526356l-5.048693,7.247362l-5.268419,-8.100027l-3.51214,9.805351z" />
</vector>

The question

Why doesn't it work? What's wrong with what I did? How can I fix it?

like image 533
android developer Avatar asked Apr 10 '16 09:04

android developer


1 Answers

As it seems, this is a bug in the way the support library works, and it's not documented in any way.

I've tried to post a bug report about it, but Google marked it as UserError, even though I don't see it documented, or have any kind of warning:

Working as intended. Vectors are not supported in containers unless you turn on AppComaptDelegate.setCompatVectorFromResourcesEnabled(true).

https://code.google.com/p/android/issues/detail?id=210745

So, if you see a selector that doesn't get shown, or that causes a crash with this log:

Caused by: android.content.res.Resources$NotFoundException: File res/drawable/selector.xml from drawable resource ID #0x7f02004f

you should either avoid using vectorDrawable within a selector, or avoid using the vectorDrawables.useSupportLibrary=true line.

You could use AppComaptDelegate.setCompatVectorFromResourcesEnabled(true) , but according to the docs, this might be faulty (memory/performance issues, mainly) and is not recommended to be used at all:

Sets whether vector drawables on older platforms (< API 21) can be used within DrawableContainer resources.

When enabled, AppCompat can intercept some drawable inflation from the framework, which enables implicit inflation of vector drawables within DrawableContainer resources. You can then use those drawables in places such as android:src on ImageView, or android:drawableLeft on TextView.

This feature defaults to disabled, since enabling it can cause issues with memory usage, and problems updating Configuration instances. If you update the configuration manually, then you probably do not want to enable this. You have been warned.

Even with this disabled, you can still use vector resources through setImageResource(int) and it's app:srcCompat attribute. They can also be used in anything which AppComapt inflates for you, such as menu resources.

Please note: this only takes effect in Activities created after this call.

like image 114
android developer Avatar answered Oct 16 '22 21:10

android developer