Android Selector Drawable with VectorDrawables srcCompat

后端 未结 5 1094
轻奢々
轻奢々 2020-12-04 08:50

I\'m facing a problem with the new backward compatibility with VectorDrawables. In the Support Library 23.2 was a new feature for backward compatibility with Android VectorD

相关标签:
5条回答
  • 2020-12-04 08:56

    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.

    0 讨论(0)
  • 2020-12-04 09:04

    I suggest this workaround to make the color change based on state: Set a normal, white VectorDrawable, and have the tint have the color selector.

    This was tested to work even on emulator with Android API 16, and it works even if you set "vectorDrawables.useSupportLibrary = true" in gradle, of course.

    Example: first view is enabled, and the second is disabled:

    MainActivity.kt

    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            disabledSendMessageButton.isEnabled = false
        }
    }
    

    res/layout/activity_main.xml

    <LinearLayout 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:clipChildren="false"
        android:clipToPadding="false" android:gravity="center" android:orientation="vertical" tools:context=".MainActivity">
    
        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/sendMessageButton" android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:clickable="true" android:focusable="true" android:foreground="?attr/selectableItemBackgroundBorderless"
            android:minWidth="?attr/actionBarSize" android:minHeight="?attr/actionBarSize" android:padding="8dp"
            android:scaleType="centerInside" app:srcCompat="@drawable/ic_baseline_send_24" app:tint="@color/color_selector"
            tools:targetApi="m" />
    
        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/disabledSendMessageButton" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:clickable="true" android:focusable="true"
            android:foreground="?attr/selectableItemBackgroundBorderless" android:minWidth="?attr/actionBarSize"
            android:minHeight="?attr/actionBarSize" android:padding="8dp" android:scaleType="centerInside"
            app:srcCompat="@drawable/ic_baseline_send_24" app:tint="@color/color_selector" tools:targetApi="m" />
    </LinearLayout>
    

    res/color/color_selector.xml

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="@android:color/secondary_text_dark" android:state_enabled="false" />
        <item android:color="@color/colorPrimary" />
    </selector>
    

    res/drawable/ic_baseline_send_24.xml

    <vector android:height="24dp" android:tint="#FFFFFF"
        android:viewportHeight="24.0" android:viewportWidth="24.0"
        android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
        <path android:fillColor="@android:color/white" android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
    </vector>
    
    0 讨论(0)
  • 2020-12-04 09:11

    As @Jahnold mentioned in the comment to question, support for loading vector drawable from an xml state xml list was removed in 23.3.

    However, I found several approaches that can help.

    1. Using Tint

    The approach is suitable if the drawables from selected state list difference only by colors.

    First, create only one vector drawable with tint and white fillColor:

    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24"
        android:viewportHeight="24"
        android:tintMode="multiply"
        android:tint="@color/button_tint">
    
        <path
            android:fillColor="#ffffff"
            android:pathData="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
    
        <path
            android:pathData="M0 0h24v24H0z"/>
    
    </vector>
    

    Second, create color state list button_tint.xml placed in res/color

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="#555555" android:state_enabled="false"/>
        <item android:color="#6699dd"/>
    </selector>
    

    Don't forget add follow lines to build.gradle or the approach will not work on old Android versions.

    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
    

    2. Hardcode creating StateListDrawable

    The approach is suitable if you use for the state list vector drawables which difference not only a color but also by a figure so you need create several different xml files. Then you can create StateListDrawable programmatically as shown in an answer.

    0 讨论(0)
  • 2020-12-04 09:19

    Working fine with below changes.

    static {
     AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }
    

    Added in Application class.
    app build.gradle inside defaultConfig

    vectorDrawables.useSupportLibrary = true
    
    0 讨论(0)
  • 2020-12-04 09:20

    After watching What's new in the support library - Google I/O 2016 I noticed one useful method in the AppCompatResources class. This is AppCompatResources#getColorStateList(Context context, int resId). With a help of this method I've implemented selector with vector drawables. Here is my color selector file icon_selector:

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="@color/red_selected" android:state_selected="true"/>
        <item android:color="@color/red_pressed" android:state_pressed="true"/>
        <item android:color="@color/red"/>
    </selector>
    

    And there is java method that returns tinted drawable:

    private Drawable getTintedDrawable(@DrawableRes int drawableId) {
        Drawable drawable;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            drawable = getResources().getDrawable(drawableId, getTheme());
        } else {
            drawable = getResources().getDrawable(drawableId);
        }
        drawable = DrawableCompat.wrap(drawable);
        DrawableCompat.setTintList(drawable.mutate(), AppCompatResources.getColorStateList(this, R.color.selector_nav_bar_item_ico));
        return drawable;
    }
    

    You can use it like shown below

    yourImageView.setImageDrawable(getTintedDrawable(R.drawable.ic_vector_image));
    
    0 讨论(0)
提交回复
热议问题