在Android上对视图背景颜色进行动画处理


335

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

例如:

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

如果无法使用视图完成此操作,将欢迎使用其他方法。


11
人们会希望,对于Android之类的平台,颜色之间的平滑过渡不应该成为问题。不过,也许不是为此而建的。问题仍然存在。
hpique 2010年

1
一个很好的视频教程
Alex Jolig '17

Answers:


374

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

您可以使用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>

然后,在实际视图的XML中,您将在android:background属性中引用该TransitionDrawable 。

此时,您可以通过执行以下操作来在代码中启动过渡:

TransitionDrawable transition = (TransitionDrawable) viewObj.getBackground();
transition.startTransition(transitionTime);

或通过调用反向运行过渡:

transition.reverseTransition(transitionTime);

有关使用Property Animation API的另一种解决方案,请参阅Roman的答案,该解决方案最初发布时尚不可用。


3
谢谢mxrider!这确实回答了问题。不幸的是,它对我不起作用,因为以TransitionDrawable为背景的视图也必须进行动画处理,并且该视图动画似乎覆盖了背景过渡。有任何想法吗?
hpique 2010年

6
通过在开始动画后启动TransitionDrawable来解决它。
hpique 2010年

2
太棒了!真高兴你做到了!您可以在Android的xml中做很多很酷的事情-其中很多都隐藏在文档中,在我看来并不明显。
偶像

4
一点都不明显。我应该提到的是,由于颜色是动态的,因此我不使用xml。如果您通过代码创建TransitionDrawable,则您的解决方案也将起作用。
hpique 2010年

2
主要缺点之一是没有动画完整的侦听器
Leo Droidcoder

509

您可以将新的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();

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

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

  • 如果使用支持库,则需要将getColor呼叫替换为:

    ContextCompat.getColor(this, R.color.red);
  • 如果您不使用支持库,则需要将getColor调用替换为:

    getColor(R.color.red);

2
如果您使用的是Property Animation API(或NineOldAndroid),则为“ musthave”解决方案。动画非常流畅。
德米特里·扎伊采夫2014年

1
有什么办法可以这样设置过渡的持续时间吗?
iGio90 2014年

159
@ iGio90是的,您不会相信它,但是方法调用setDuration():)
Roman Minenok

6
ValueAnimator.ofArgb(colorFrom, colorTo)看起来更重要,但可惜它是新的。
TWiStErRob '16

1
美丽的解决方案!谢谢。
史蒂夫·弗利

137

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

前两个使用Android Property Animation框架。

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

  • 您的视图的背景色定义为argbxml文件中的值。
  • 您的视图之前的颜色设置为 view.setBackgroundColor()
  • 视图的背景色在可绘制对象中定义,该对象定义任何额外的属性,例如笔触或拐角半径。
  • 视图的背景色在可绘制对象中定义,并且要删除任何额外的属性,例如笔触或拐角半径,请记住,删除这些额外的属性不会产生动画效果。

对象动画师通过调用view.setBackgroundColor来工作,该对象替换已定义的drawable,除非它是a的实例ColorDrawable,而它很少是。这意味着将删除可绘制对象中任何多余的背景属性(例如笔触或拐角)。

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

  • 视图的背景颜色在可绘制对象中定义,该对象还设置了笔触或拐角半径等属性,并且您想将其更改为在运行时确定的新颜色。

如果满足以下条件,则使用Transition绘制

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

我在打开无法解决的DrawerLayout时运行的Transition可绘制对象遇到一些性能问题,因此,如果遇到任何意外的卡顿现象,可能会遇到与我相同的错误。

如果要使用StateLists可绘制对象LayerLists可绘制对象,则必须修改Value Animator示例,否则它将崩溃final 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();

您还可以使用AnimatorInflater从xml加载xml中的动画定义,就像XMight在Android object中所做的那样。

价值动画师

查看定义:

<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。


实际上,可以在代码中定义和使用TransitionDrawable,但是由于某种原因,它第二次不起作用。奇怪的。
android开发人员

即使我的视图设置了ColorDrawable,我也可以使用对象动画器。我只是将其保存到局部变量,将其设置为null,然后在完成动画后,将原始ColorDrawable设置回去。
米洛什·切尔尼洛夫斯基

55

您可以使对象成为动画师。例如,我有一个targetView,我想更改您的背景色:

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

2
在API 21中,您可以使用ofArgb(targetView, "backgroundColor", colorFrom, colorTo)。它的实现是公正的ofInt(...).setEvaluator(new ArgbEvaluator())
ypresto

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();

9
初始化anim变量的部位在哪里?
2016年

@VoW,它只是ValueAnimator的实例。
RBK

anim.setRepeatCount(ValueAnimator.INFINITE);现在不应该是Animation.INFINITE,现在还是一样,但是我们不能保证
MikhailKrishtop

@MikhailKrishtop Animation.INFINITE有什么问题?developer.android.com/reference/android/view/animation/…–
RBK

14

最好的方法是使用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();

12

实现此目的的另一种简便方法是使用AlphaAnimation执行淡入。

  1. 使您的视图成为ViewGroup
  2. 将子视图添加到索引0,具有match_parent布局尺寸
  3. 给孩子提供与容器相同的背景
  4. 将容器的背景更改为目标颜色
  5. 使用AlphaAnimation淡出孩子。
  6. 动画完成后删除子级(使用AnimationListener)

那是一个把戏!做得好 。。。
elyar abad

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);
            }
        }
    }

更新:如果有人遇到相同的问题,出于某种原因,在Android <4.3上使用setCrossFadeEnabled(true)会导致不良的泛白效果,因此我不得不使用上述@Roman Minenok ValueAnimator方法切换为<4.3的纯色。


这正是我想要的。谢谢!:)
cyph3r 2014年

7

答案有很多方式。您还可以使用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();

7

有关XML驱动的动画的文档太可怕了。我搜索了大约几个小时,只是为了在按下时为按钮的背景色设置动画。可悲的是,动画只是一个属性而已:您可以exitFadeDuration在中使用selector

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

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


你救了我的日子。谢谢。
费德里科·海兰德

1
极好的答案。请注意,您可能还需要android:enterFadeDuration;我的经验是,没有它,我的动画将无法第二次运行。
字符串

7

这是一个不错的功能,它可以实现以下目的:

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();
    }
}

在科特林:

@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()
    }
}

这不支持低端版本的手机
Kartheek的

2
@Kartheeks您的意思是Android 10及更低版本?如果是这样,您可以轻松地使用“ nineOldAndroids”库来支持它:nineoldandroids.com。语法几乎完全相同。
Android开发人员

对于较低版本的colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){@Override public void onAnimationUpdate(ValueAnimator animation){colorDrawable.setColor((Integer)animation.getAnimatedValue()); ViewCompat.setBackground(viewToAnimateItsBackground,colorDrawable);}}) ;
Mahbubur Ra​​hman Khan

5

将文件夹动画器添加到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();

3

对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()
}

通过任何您想更改颜色的视图。


2

我发现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();

但是,如果您像我一样,并且希望将过渡与输入中传递的某些用户手势或其他值相关联,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))));
}

并根据需要使用它。


0

基于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();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.