How to change color of vector drawable path on button click

后端 未结 9 1779
北荒
北荒 2020-12-01 00:33

With the new android support update, vector drawables get backward compatibility. I have a vector image with various paths. I want the color of the paths to change on click

相关标签:
9条回答
  • 2020-12-01 01:09

    DrawableCompat.setTint(imageView.getDrawable(),ContextCompat.getColor(getApplicationContext(), R.color.colorAccent));

    0 讨论(0)
  • 2020-12-01 01:14

    As stated by @Eyal in this post https://stackoverflow.com/a/32007436/4969047

    You cannot change the color of individual path at runtime. Looking at the source code of VectorDrawableCompat, the only method to expose the inner element by name is getTargetByName which is present in inner private state class VectorDrawableCompatState of VectorDrawableCompat.

    Since it is a package private (default) - you can't use it (unless you use reflection).

    0 讨论(0)
  • 2020-12-01 01:15

    The color of the whole vector can be changed using setTint.

    You have to set up your ImageView in your layout file as this:

    <ImageView
        android:id="@+id/myImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:tint="@color/my_nice_color"
        android:src="@drawable/ic_my_drawable"
        android:scaleType="fitCenter" />
    

    Then to change the color of your image:

    DrawableCompat.setTint(myImageView.getDrawable(), ContextCompat.getColor(context, R.color.another_nice_color));
    

    Note: myImageView.getDrawable() gives nullpointerexception if the vector drawable is set to the imageView as background.

    0 讨论(0)
  • 2020-12-01 01:20

    You can achieve this without a library, and combine Data Binding with Kotlin.

    ButtonBinding.kt

        @SuppressLint("PrivateResource")
        @BindingAdapter("drawable:start", "drawable:color", "button:isClicked", requireAll = false)
        @JvmStatic
        fun Button.setDrawableStartColor(@DrawableRes start: Int, @ColorRes color: Int, isClicked: Boolean) {
            this.apply btn@{
            context.apply ctx@{
                val drawable = ContextCompat
                        .getDrawable(this, start)
                        ?.apply {
                            if (isClicked) {
                                setColorFilter(
                                        ContextCompat.getColor(this@ctx, color),
                                        PorterDuff.Mode.SRC_ATOP)
                            }
                        }
    
                setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
            }
            }
        }
    

    You can directly use setCompoundDrawablesWithIntrinsicBounds or setCompoundDrawables( but you have to define the current intrinsic bound, check out this article here

    my_fragment.xml

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:drawable="http://schemas.android.com/apk/res-auto">
    
        <data>
    
            <import type="your.package.R"/>
    
            <variable
                name="actionListener"
                type="your.package.mvvmV2.account.profile.ProfileActionListener"/>
    
            <variable
                name="profileResponse"
                type="your.package.data.model.ProfileResponse"/>
    
            <variable
                name="viewModel"
                type="your.package.mvvmV2.home.HomeViewModel"/>
        </data>
                <Button
                    drawable:color="@{R.color.white}"
                    drawable:start="@{R.drawable.ic_person_blue}"
                    android:id="@+id/buttonProfile"
    </layout>
    

    For setup click listener, you can do this following as well:

    YourFragment.kt

        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
            mViewBinding = AccountFragmentV2Binding
                    .inflate(inflater, container, false)
                    .apply {
                        viewModel = mViewModel // also, assign the correct view model to your xml
                        actionListener = this@AccountFragment
                        setLifecycleOwner(this@AccountFragment) // don't forget this
                    }
    
            return mViewBinding.root
        }
    
        override fun onProfileClicked(v: View) {
            mViewBinding.apply {
                mViewModel.let {
                    // change and store the state, but don't forget to reset to default
                    it.clickState[R.drawable.v2_ic_person_blue] = v.isPressed
                }
                executePendingBindings() // update ui directly, without delays
            }
        }
    
    

    ViewModel.kt

    val clickState = ObservableArrayMap<Int, Boolean>()
    
        init {
            clickState[R.drawable.ic_aktivitas_blue] = false
            clickState[R.drawable.ic_person_blue] = false
            clickState[R.drawable.ic_bookmark_blue] = false
        }
    
    

    Define the binding adapter with integer resource instead of using @color/ or @drawable. If you prefer using @ annotation (e.g: drawable:start="@{@drawable/id}") on the XML.

    Change the data binding like this

    fun Button.setDrawable(start: Drawable, color: Color) {
    // do the conversion to int id, it will be a mess. that's why I stick to receive int id from resource instead
    }
    

    Also, don't forget to set up this from @aminography

    Important Point in Using Android Vector Drawable When you are using an android vector drawable and want to have backward compatibility for API below 21, add the following codes to

    In app level build.gradle:

    android {
        defaultConfig {
            vectorDrawables.useSupportLibrary = true
        }
    }
    

    In Application class:

    class MyApplication : Application() {
    
        override fun onCreate() {
            super.onCreate()
    
            AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
        }
    
    }
    

    Thanks to this answer here, @Varun here explained any other alternative, the original answer for my case here

    0 讨论(0)
  • 2020-12-01 01:21

    There are several ways of doing the same stuff, but this works for both Vector Drawables as well as SVG (Local/Network).

    imageView.setColorFilter(ContextCompat.getColor(context, 
    R.color.headPink), android.graphics.PorterDuff.Mode.SRC_IN);
    

    (change R.color.headPink with color of your choice)

    0 讨论(0)
  • 2020-12-01 01:24

    Use this to change a path color in your vector drawable

    VectorChildFinder vector = new VectorChildFinder(this, R.drawable.my_vector, imageView);
    
    VectorDrawableCompat.VFullPath path1 = vector.findPathByName("path1");
    path1.setFillColor(Color.RED); 
    

    Library is here: https://github.com/devsideal/VectorChildFinder

    0 讨论(0)
提交回复
热议问题