如何在按钮单击时更改矢量可绘制路径的颜色

问题描述 投票:34回答:8

随着新的Android支持更新,矢量drawables获得向后兼容性。我有一个带有各种路径的矢量图像。我希望通过单击按钮或基于输入值以编程方式更改路径的颜色。是否可以访问矢量路径的name参数?然后改变颜色。

android vector vector-graphics android-vectordrawable
8个回答
16
投票

使用此选项可更改矢量drawable中的路径颜色

VectorChildFinder vector = new VectorChildFinder(this, R.drawable.my_vector, imageView);

VectorDrawableCompat.VFullPath path1 = vector.findPathByName("path1");
path1.setFillColor(Color.RED); 

图书馆在这里:https://github.com/devsideal/VectorChildFinder


49
投票

可以使用setTint更改整个矢量的颜色。

您必须在布局文件中设置ImageView,如下所示:

<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" />

然后更改图像的颜色:

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

注意:如果向量drawable设置为imageView作为背景,则myImageView.getDrawable()会给出nullpointerexception。


5
投票

您可以使用此方法更改较低API中的颜色以更改片段中的矢量颜色

int myVectorColor = ContextCompat.getColor(getActivity(), R.color.colorBlack);
                    myButton.getIcon().setColorFilter(myVectorColor, PorterDuff.Mode.SRC_IN);

代替getActivity,你应该使用MainActivity.this来改变活动中的矢量颜色


2
投票

您可以在运行时更改单个路径的颜色,而无需使用反射。

VectorMaster引入了对矢量绘图的动态控制。可以使用此库动态地(通过Java实例)控制矢量drawable的每个方面。

只需在应用程序的build.gradle中添加以下依赖项

dependencies {
    compile 'com.sdsmdg.harjot:vectormaster:1.0.9'
}

在您的情况下,您需要一个简单的颜色变化:

矢量示例:your_vector.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0">
<path
    android:name="outline"
    android:pathData="M20.84,4..."
    android:strokeColor="#5D5D5D"
    android:fillColor="#00000000"
    android:strokeWidth="2"/>

XML:

<com.sdsmdg.harjot.vectormaster.VectorMasterView
    android:id="@+id/your_vector"
    android:layout_width="150dp"
    android:layout_height="150dp"
    app:vector_src="@drawable/your_drawable" />

Java的:

VectorMasterView heartVector = (VectorMasterView) 
findViewById(R.id.your_drawable);

// find the correct path using name
PathModel outline = heartVector.getPathModelByName("outline");

// set the stroke color
outline.setStrokeColor(Color.parseColor("#ED4337"));

// set the fill color (if fill color is not set or is TRANSPARENT, then no fill is drawn)
outline.setFillColor(Color.parseColor("#ED4337"));

来自:https://github.com/harjot-oberai/VectorMaster,在麻省理工学院获得许可。

您现在可以完全控制矢量绘图。


2
投票

有几种方法可以做同样的事情,但这适用于Vector Drawables和SVG(Local / Network)。

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

(使用您选择的颜色更改R.color.headPink)


1
投票

在另一个问题上检查我的答案:https://stackoverflow.com/a/38418049/1335438

如何通过使用主题和参数化路径来管理它是一个很好的主意,以便能够动态设置它们。


0
投票

正如@Eyal在这篇文章https://stackoverflow.com/a/32007436/4969047所述

您无法在运行时更改单个路径的颜色。查看VectorDrawableCompat的源代码,通过名称公开内部元素的唯一方法是getTargetByName,它存在于VectorDrawableCompatState的内部私有状态类VectorDrawableCompat中。

由于它是一个包私有(默认) - 你不能使用它(除非你使用reflection)。


0
投票

您可以在没有库的情况下实现此目的,并将Data Binding与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)
        }
        }
    }

你可以直接使用setCompoundDrawablesWithIntrinsicBounds或setCompoundDrawables(但是你必须定义当前的内部边界,看看这篇文章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>

对于安装点击监听器,您也可以执行以下操作:

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
    }

使用整数资源定义绑定适配器,而不是使用@ color /或@drawable。如果您更喜欢在XML上使用@ annotation(例如:drawable:start="@{@drawable/id}")。

像这样更改数据绑定

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
}

另外,不要忘记从@aminography设置this

使用Android矢量Drawable的重点当您使用Android矢量drawable并希望对21以下的API具有向后兼容性时,请将以下代码添加到

在app level build.gradle中:

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

在Application类中:

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
    }

}

感谢这个answer here@Varun here explained any other alternative,我的案例here的原始答案

© www.soinside.com 2019 - 2024. All rights reserved.