Android上视图背景颜色的动画更改

hpi*_*que 313 animation android view background-color

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

例如:

我有一个红色背景颜色的视图.视图的背景颜色变为蓝色.如何在颜色之间进行平滑过渡?

如果无法通过视图进行此操作,则欢迎使用其他选项.

Rom*_*nok 482

您可以使用新的Property Animation Api进行颜色动画:

int colorFrom = getResources().getColor(R.color.red);
int colorTo = getResources().getColor(R.color.blue);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.setDuration(250); // milliseconds
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(ValueAnimator animator) {
        textView.setBackgroundColor((int) animator.getAnimatedValue());
    }

});
colorAnimation.start();
Run Code Online (Sandbox Code Playgroud)

为了向后兼容Android 2.x,请使用Jake Wharton的Nine Old Androids库.

getColor方法在Android M中已弃用,因此您有两种选择:

  • @ iGio90是的,你不是不相信它,但方法调用setDuration():) (150认同)
  • `ValueAnimator.ofArgb(colorFrom,colorTo)`看起来更加重要,但遗憾的是它是新的. (6认同)
  • 如果您正在使用Property Animation API(或NineOldAndroid),那么"必须"解决方案.动画非常流畅. (2认同)
  • 要获取布局的当前背景颜色,请使用此代码。`((ColorDrawable)frame_layout.getBackground()).getColor()` (2认同)

ido*_*ize 353

我最终找到了解决这个问题的(相当不错的)解决方案!

您可以使用TransitionDrawable来完成此任务.例如,在drawable文件夹中的XML文件中,您可以编写如下内容:

<?xml version="1.0" encoding="UTF-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- The drawables used here can be solid colors, gradients, shapes, images, etc. -->
    <item android:drawable="@drawable/original_state" />
    <item android:drawable="@drawable/new_state" />
</transition>
Run Code Online (Sandbox Code Playgroud)

然后,在实际View的XML中,您将在android:background属性中引用此TransitionDrawable .

此时,您可以通过执行以下操作来启动代码on-command中的转换:

TransitionDrawable transition = (TransitionDrawable) viewObj.getBackground();
transition.startTransition(transitionTime);
Run Code Online (Sandbox Code Playgroud)

或者通过调用以反向运行转换:

transition.reverseTransition(transitionTime);
Run Code Online (Sandbox Code Playgroud)

请参阅Roman对使用Property Animation API的另一种解决方案的回答,该解决方案最初发布时尚未提供.

  • 通过在启动动画后启动TransitionDrawable来解决它. (6认同)
  • 根本不明显.我应该提一下,我不是在我的情况下使用xml,因为颜色是动态的.如果您通过代码创建TransitionDrawable,则您的解决方案也适用. (4认同)
  • 谢谢mxrider!这确实回答了这个问题.不幸的是它对我不起作用,因为具有TransitionDrawable作为背景的视图也必须被动画化,并且看起来视图动画会覆盖背景过渡.有任何想法吗? (3认同)
  • 真棒!真高兴你做到了!你可以用xml在Android中做很多很酷的东西 - 其中很多都有点埋没在文档中,在我看来并不明显. (2认同)
  • 主要缺点之一是没有动画完整的侦听器 (2认同)
  • 是否可以制作超过 2 种颜色的动画? (2认同)

Mat*_*ias 132

根据视图获取背景颜色的方式以及获取目标颜色的方式,有几种不同的方法可以实现.

前两个使用Android Property Animation框架.

如果出现以下情况,请使用Object Animator:

  • 您的视图将其背景颜色定义为argbxml文件中的值.
  • 您的视图之前已经设置了颜色 view.setBackgroundColor()
  • 您的视图的背景颜色在drawable中定义,不会定义任何额外的属性,如笔划或角半径.
  • 您的视图的背景颜色在drawable中定义,并且您想要删除任何额外的属性,如笔划或角半径,请记住,删除额外的属性不会动画.

对象动画师通过调用view.setBackgroundColor来替换定义的drawable,除非它是a的实例ColorDrawable,它很少.这意味着将删除诸如笔划或角落之类的可绘制的任何额外背景属性.

如果出现以下情况,请使用Value Animator:

  • 您的视图在drawable中定义了背景颜色,该颜色还设置了笔触或角半径等属性,并且您希望将其更改为运行时决定的新颜色.

在以下情况下使用Transition drawable:

  • 您的视图应在部署之前定义的两个drawable之间切换.

在我打开一个我无法解决的DrawerLayout时运行的Transition drawables遇到了一些性能问题,所以如果你遇到任何意想不到的口吃,你可能遇到了和我一样的bug.

如果要使用StateLists drawableLayerLists drawable,则必须修改Value Animator示例,否则它将在该final GradientDrawable background = (GradientDrawable) view.getBackground();行上崩溃.

对象动画师:

查看定义:

<View
    android:background="#FFFF0000"
    android:layout_width="50dp"
    android:layout_height="50dp"/>
Run Code Online (Sandbox Code Playgroud)

创建并使用ObjectAnimator这样的.

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

您还可以使用AnimatorInflater从xml加载动画定义,例如XMight在Android objectAnimator中设置动画backgroundColor of Layout

价值动画师:

查看定义:

<View
    android:background="@drawable/example"
    android:layout_width="50dp"
    android:layout_height="50dp"/>
Run Code Online (Sandbox Code Playgroud)

可绘定义:

<?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>
Run Code Online (Sandbox Code Playgroud)

像这样创建和使用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();
Run Code Online (Sandbox Code Playgroud)

转换drawable:

查看定义:

<View
    android:background="@drawable/example"
    android:layout_width="50dp"
    android:layout_height="50dp"/>
Run Code Online (Sandbox Code Playgroud)

可绘定义:

<?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>
Run Code Online (Sandbox Code Playgroud)

像这样使用TransitionDrawable:

final TransitionDrawable background = (TransitionDrawable) view.getBackground();
background.startTransition(300);
Run Code Online (Sandbox Code Playgroud)

您可以通过调用.reverse()动画实例来反转动画.

还有一些其他方法可以做动画,但这三种可能是最常见的.我通常使用ValueAnimator.


ade*_*190 53

你可以制作一个物体动画师.例如,我有一个targetView,我想改变你的背景颜色:

int colorFrom = Color.RED;
int colorTo = Color.GREEN;
int duration = 1000;
ObjectAnimator.ofObject(targetView, "backgroundColor", new ArgbEvaluator(), colorFrom, colorTo)
    .setDuration(duration)
    .start();
Run Code Online (Sandbox Code Playgroud)

  • 从 API 21 开始,您可以使用 `ofArgb(targetView, "backgroundColor", colorFrom, colorTo)`。它的实现只是`ofInt(...).setEvaluator(new ArgbEvaluator())`。 (3认同)

RBK*_*RBK 20

如果你想要这样的彩色动画,

在此输入图像描述

此代码将帮助您:

ValueAnimator anim = ValueAnimator.ofFloat(0, 1);   
anim.setDuration(2000);

float[] hsv;
int runColor;
int hue = 0;
hsv = new float[3]; // Transition color
hsv[1] = 1;
hsv[2] = 1;
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {

        hsv[0] = 360 * animation.getAnimatedFraction();

        runColor = Color.HSVToColor(hsv);
        yourView.setBackgroundColor(runColor);
    }
});

anim.setRepeatCount(Animation.INFINITE);

anim.start();
Run Code Online (Sandbox Code Playgroud)

  • **anim**变量初始化时的部分在哪里? (9认同)

Mar*_*ius 15

XML 驱动动画的文档非常糟糕。我已经搜索了大约几个小时,只是为了在按下按钮时为按钮的背景颜色设置动画……可悲的是,动画只有一个属性:您可以exitFadeDurationselector

<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:exitFadeDuration="200">

    <item android:state_pressed="true">
        <shape android:tint="#3F51B5" />
    </item>

    <item>
        <shape android:tint="#F44336" />
    </item>

</selector>
Run Code Online (Sandbox Code Playgroud)

然后将其用作background您的视图。不需要 Java/Kotlin 代码。

  • 很好的答案。请注意,您可能还需要`android:enterFadeDuration`;我的经验是,如果没有它,我的动画第二次就无法工作。 (3认同)

Ras*_*iri 12

最好的方法是使用ValueAnimatorColorUtils.blendARGB

 ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
 valueAnimator.setDuration(325);
 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {

              float fractionAnim = (float) valueAnimator.getAnimatedValue();

              view.setBackgroundColor(ColorUtils.blendARGB(Color.parseColor("#FFFFFF")
                                    , Color.parseColor("#000000")
                                    , fractionAnim));
        }
});
valueAnimator.start();
Run Code Online (Sandbox Code Playgroud)


Ste*_*AIS 11

另一种实现此目的的简单方法是使用AlphaAnimation执行淡入淡出.

  1. 使您的视图成为ViewGroup
  2. 在索引0处添加子视图,并使用match_parent布局维度
  3. 为您的孩子提供与容器相同的背景
  4. 将容器的背景更改为目标颜色
  5. 使用AlphaAnimation淡出孩子.
  6. 动画完成后删除子项(使用AnimationListener)


sco*_*yab 9

这是我在基本活动中用于更改背景的方法.我正在使用在代码中生成的GradientDrawables,但可以适应.

    protected void setPageBackground(View root, int type){
        if (root!=null) {
            Drawable currentBG = root.getBackground();
            //add your own logic here to determine the newBG 
            Drawable newBG = Utils.createGradientDrawable(type); 
            if (currentBG==null) {
                if(Build.VERSION.SDK_INT<Build.VERSION_CODES.JELLY_BEAN){
                    root.setBackgroundDrawable(newBG);
                }else{
                    root.setBackground(newBG);
                }
            }else{
                TransitionDrawable transitionDrawable = new TransitionDrawable(new Drawable[]{currentBG, newBG});
                transitionDrawable.setCrossFadeEnabled(true);
                if(Build.VERSION.SDK_INT<Build.VERSION_CODES.JELLY_BEAN){
                     root.setBackgroundDrawable(transitionDrawable);
                }else{
                    root.setBackground(transitionDrawable);
                }
                transitionDrawable.startTransition(400);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

更新:如果有人遇到同样的问题我发现,由于某些原因在Android <4.3使用setCrossFadeEnabled(true)导致不良的白色效果,所以我不得不使用上面提到的@Roman Minenok ValueAnimator方法切换到<4.3的纯色.


and*_*per 8

这是一个很好的函数,允许这样做:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

在 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()
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Kartheeks 你的意思是 Android 10 及以下版本?如果是这样,您可以轻松使用“nineOldAndroids”库来支持它:http://nineoldandroids.com/。语法几乎完全相同。 (2认同)

Man*_*ddy 8

Roman Minenok在 kotlin 中的回答以及作为扩展函数

fun View.colorTransition(@ColorRes startColor: Int, @ColorRes endColor: Int, duration: Long = 250L){
    val colorFrom = ContextCompat.getColor(context, startColor)
    val colorTo =  ContextCompat.getColor(context, endColor)
    val colorAnimation: ValueAnimator = ValueAnimator.ofObject(ArgbEvaluator(), colorFrom, colorTo)
    colorAnimation.duration = duration

    colorAnimation.addUpdateListener {
        if (it.animatedValue is Int) {
            val color=it.animatedValue as Int
            setBackgroundColor(color)
        }
    }
    colorAnimation.start()
}
Run Code Online (Sandbox Code Playgroud)

如果您想从当前背景颜色更改为新颜色,则可以使用此

fun View.colorTransition(@ColorRes endColor: Int, duration: Long = 250L){
    var colorFrom = Color.TRANSPARENT
    if (background is ColorDrawable)
        colorFrom = (background as ColorDrawable).color

    val colorTo =  ContextCompat.getcolor(context, endColor)
    val colorAnimation: ValueAnimator = ValueAnimator.ofObject(ArgbEvaluator(), colorFrom, colorTo)
    colorAnimation.duration = duration

    colorAnimation.addUpdateListener {
        if (it.animatedValue is Int) {
            val color=it.animatedValue as Int
            setBackgroundColor(color)
        }
    }
    colorAnimation.start()
}
Run Code Online (Sandbox Code Playgroud)

用法

myView.colorTransition(R.color.bg_color)
Run Code Online (Sandbox Code Playgroud)


Has*_*san 8

您可以像这样使用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()
}
Run Code Online (Sandbox Code Playgroud)


Pra*_*rma 7

对 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()
}
Run Code Online (Sandbox Code Playgroud)

传递您想要更改颜色的任何视图。


Pal*_*rji 6

答案以多种方式给出.您还可以使用ofArgb(startColor,endColor)ValueAnimator.

对于API> 21:

int cyanColorBg = ContextCompat.getColor(this,R.color.cyan_bg);
int purpleColorBg = ContextCompat.getColor(this,R.color.purple_bg);

ValueAnimator valueAnimator = ValueAnimator.ofArgb(cyanColorBg,purpleColorBg);
        valueAnimator.setDuration(500);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
              @Override
              public void onAnimationUpdate(ValueAnimator valueAnimator) {
                   relativeLayout.setBackgroundColor((Integer)valueAnimator.getAnimatedValue());
              }
        });
        valueAnimator.start();
Run Code Online (Sandbox Code Playgroud)


can*_*bax 6

将文件夹动画师添加到res文件夹中。(名称必须是动画师)。添加动画资源文件。例如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>
Run Code Online (Sandbox Code Playgroud)

在 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();
Run Code Online (Sandbox Code Playgroud)


fah*_*hmy 5

我发现ArgbEvaluatorAndroid 源代码中使用的实现在颜色转换方面做得最好。使用 HSV 时,根据两种颜色,过渡对我来说跳过了太多的色调。但是这个方法不行。

如果您想简单地制作动画,请按照此处的建议使用ArgbEvaluatorwith :ValueAnimator

ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(ValueAnimator animator) {
        view.setBackgroundColor((int) animator.getAnimatedValue());
    }

});
colorAnimation.start();
Run Code Online (Sandbox Code Playgroud)

但是,如果您像我一样并且想要将您的转换与从输入传递的某些用户手势或其他值联系起来,这ValueAnimator并没有太大帮助(除非您的目标是 API 22 及更高版本,在这种情况下您可以使用该ValueAnimator.setCurrentFraction()方法)。当面向 API 22 以下时,将ArgbEvaluator源代码中的代码包装在您自己的方法中,如下所示:

public static int interpolateColor(float fraction, int startValue, int endValue) {
    int startA = (startValue >> 24) & 0xff;
    int startR = (startValue >> 16) & 0xff;
    int startG = (startValue >> 8) & 0xff;
    int startB = startValue & 0xff;
    int endA = (endValue >> 24) & 0xff;
    int endR = (endValue >> 16) & 0xff;
    int endG = (endValue >> 8) & 0xff;
    int endB = endValue & 0xff;
    return ((startA + (int) (fraction * (endA - startA))) << 24) |
            ((startR + (int) (fraction * (endR - startR))) << 16) |
            ((startG + (int) (fraction * (endG - startG))) << 8) |
            ((startB + (int) (fraction * (endB - startB))));
}
Run Code Online (Sandbox Code Playgroud)

并随心所欲地使用它。