如何在Android上动画化视图的背景颜色变化?

例如:

我有一个红色背景色的视图。视图的背景颜色变为蓝色。我怎样才能在颜色之间平滑过渡呢?

如果视图不能做到这一点,那么另一种选择是受欢迎的。


当前回答

根据视图获取背景颜色的方式以及获取目标颜色的方式,有几种不同的方法可以做到这一点。

前两个使用Android属性动画框架。

在以下情况下使用对象动画器:

视图的背景颜色定义为xml文件中的argb值。 你的视图之前已经由view设置了它的颜色。 视图的背景颜色定义在一个drawable中,它没有定义任何额外的属性,如笔画或角半径。 你的视图有它的背景颜色定义在一个可绘制的,你想要删除任何额外的属性,如笔画或角半径,请记住,删除额外的属性将不会动画。

对象动画器通过调用view来工作。setBackgroundColor替换已定义的drawable,除非它是ColorDrawable的实例,但它很少是。这意味着任何来自可绘制对象的额外背景属性(如描边或角)都将被删除。

在以下情况下使用值动画器:

你的视图有它的背景颜色定义在一个可绘制的,还设置属性,如笔画或角半径和你想改变它为一个新的颜色,这是在运行时决定的。

在以下情况下使用过渡绘制:

视图应该在部署前定义的两个可绘制对象之间切换。

我有一些性能问题与过渡绘图运行,而我正在打开一个抽屉布局,我还没有能够解决,所以如果你遇到任何意外的口吃,你可能会遇到相同的bug,我有。

如果你想使用StateLists可绘制对象或LayerLists可绘制对象,你必须修改Value Animator的例子,否则它会在最终的GradientDrawable background = (GradientDrawable) view.getBackground();线。

对象动画:

视图定义:

<View
    android:background="#FFFF0000"
    android:layout_width="50dp"
    android:layout_height="50dp"/>

像这样创建并使用一个ObjectAnimator。

final ObjectAnimator backgroundColorAnimator = ObjectAnimator.ofObject(view,
                                                                       "backgroundColor",
                                                                       new ArgbEvaluator(),
                                                                       0xFFFFFFFF,
                                                                       0xff78c5f9);
backgroundColorAnimator.setDuration(300);
backgroundColorAnimator.start();

你也可以从xml中使用AnimatorInflater加载动画定义,就像XMight在Android中的objectAnimator animate backgroundColor of Layout

动画师的值:

视图定义:

<View
    android:background="@drawable/example"
    android:layout_width="50dp"
    android:layout_height="50dp"/>

可拉的定义:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#FFFFFF"/>
    <stroke
        android:color="#edf0f6"
        android:width="1dp"/>
    <corners android:radius="3dp"/>

</shape>

像这样创建并使用ValueAnimator:

final ValueAnimator valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(),
                                                           0xFFFFFFFF,
                                                           0xff78c5f9);

final GradientDrawable background = (GradientDrawable) view.getBackground();
currentAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(final ValueAnimator animator) {
        background.setColor((Integer) animator.getAnimatedValue());
    }

});
currentAnimation.setDuration(300);
currentAnimation.start();

可拉的转变:

视图定义:

<View
    android:background="@drawable/example"
    android:layout_width="50dp"
    android:layout_height="50dp"/>

可拉的定义:

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="#FFFFFF"/>
            <stroke
                android:color="#edf0f6"
                android:width="1dp"/>
            <corners android:radius="3dp"/>
        </shape>
    </item>

    <item>
        <shape>
            <solid android:color="#78c5f9"/>
            <stroke
                android:color="#68aff4"
                android:width="1dp"/>
            <corners android:radius="3dp"/>
        </shape>
    </item>
</transition>

像这样使用TransitionDrawable:

final TransitionDrawable background = (TransitionDrawable) view.getBackground();
background.startTransition(300);

你可以通过在动画实例上调用.reverse()来反转动画。

还有其他制作动画的方法,但这三种可能是最常见的。我通常使用ValueAnimator。

其他回答

你可以像这样使用ValueAnimator:

 fun startColorAnimation(v: View) {
    val colorStart = v.solidColor
    val colorEnd = Color.RED
    val colorAnim: ValueAnimator = ObjectAnimator.ofInt(v, "backgroundColor", colorStart, colorEnd)
    colorAnim.setDuration(1000)
    colorAnim.setEvaluator(ArgbEvaluator())
    colorAnim.repeatCount = 1
    colorAnim.repeatMode = ValueAnimator.REVERSE
    colorAnim.start()
}

基于ademar111190的答案,我创建了这个方法,它将在任意两种颜色之间脉冲视图的背景颜色:

private void animateBackground(View view, int colorFrom, int colorTo, int duration) {


    ObjectAnimator objectAnimator = ObjectAnimator.ofObject(view, "backgroundColor", new ArgbEvaluator(), colorFrom, colorTo);
    objectAnimator.setDuration(duration);
    //objectAnimator.setRepeatCount(Animation.INFINITE);
    objectAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {

        }

        @Override
        public void onAnimationEnd(Animator animation) {
            // Call this method again, but with the two colors switched around.
            animateBackground(view, colorTo, colorFrom, duration);
        }

        @Override
        public void onAnimationCancel(Animator animation) {

        }

        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    });
    objectAnimator.start();
}

在Kotlin中使用以下函数:

private fun animateColorValue(view: View) {
    val colorAnimation =
        ValueAnimator.ofObject(ArgbEvaluator(), Color.GRAY, Color.CYAN)
    colorAnimation.duration = 500L
    colorAnimation.addUpdateListener { animator -> view.setBackgroundColor(animator.animatedValue as Int) }
    colorAnimation.start()
}

传递任何你想改变颜色的视图。

这里有一个很好的函数可以做到这一点:

public static void animateBetweenColors(final @NonNull View viewToAnimateItsBackground, final int colorFrom,
                                        final int colorTo, final int durationInMs) {
    final ColorDrawable colorDrawable = new ColorDrawable(durationInMs > 0 ? colorFrom : colorTo);
    ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable);
    if (durationInMs > 0) {
        final ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
        colorAnimation.addUpdateListener(animator -> {
            colorDrawable.setColor((Integer) animator.getAnimatedValue());
            ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable);
        });
        colorAnimation.setDuration(durationInMs);
        colorAnimation.start();
    }
}

在Kotlin中:

@JvmStatic
fun animateBetweenColors(viewToAnimateItsBackground: View, colorFrom: Int, colorTo: Int, durationInMs: Int) {
    val colorDrawable = ColorDrawable(if (durationInMs > 0) colorFrom else colorTo)
    ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable)
    if (durationInMs > 0) {
        val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), colorFrom, colorTo)
        colorAnimation.addUpdateListener { animator: ValueAnimator ->
            colorDrawable.color = (animator.animatedValue as Int)
            ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable)
        }
        colorAnimation.duration = durationInMs.toLong()
        colorAnimation.start()
    }
}

添加一个文件夹动画到res文件夹。(名称必须是animator)。添加一个动画资源文件。例如res/animator/fade.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:propertyName="backgroundColor"
        android:duration="1000"
        android:valueFrom="#000000"
        android:valueTo="#FFFFFF"
        android:startOffset="0"
        android:repeatCount="-1"
        android:repeatMode="reverse" />
</set>

在Activity java文件中,调用这个

View v = getWindow().getDecorView().findViewById(android.R.id.content);
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.fade);
set.setTarget(v);
set.start();