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

时间:2010-04-10 18:58:39

标签: android animation view background-color

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

例如:

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

如果无法通过观点进行此操作,欢迎使用替代方案。

17 个答案:

答案 0 :(得分:459)

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

Android M中不推荐使用getColor方法,因此您有两种选择:

  • 如果您使用支持库,则需要将getColor来电替换为:

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

    getColor(R.color.red);
    

答案 1 :(得分:343)

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

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

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

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

或者通过调用:

反向运行转换
transition.reverseTransition(transitionTime);

请参阅Roman's answer以了解使用Property Animation API的其他解决方案,该解决方案最初发布时尚未提供。

答案 2 :(得分:127)

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

前两个使用Android Property Animation框架。

使用Object Animator if:

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

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

使用Value Animator if:

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

使用Transition drawable if:

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

在我打开一个我无法解决的DrawerLayout时,我遇到过Transition drawables的一些性能问题,所以如果遇到任何意外的口吃,你可能会遇到与我相同的错误。

如果您想使用StateLists drawableLayerLists drawable,则必须修改Value Animator示例,否则会在final GradientDrawable background = (GradientDrawable) view.getBackground();行崩溃。

<强> Object Animator

查看定义:

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

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

<强> Value Animator

查看定义:

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

<强> Transition drawable

查看定义:

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

答案 3 :(得分:48)

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

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

答案 4 :(得分:19)

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

Enter image description here

此代码可以帮助您:

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

答案 5 :(得分:11)

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

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

答案 6 :(得分:9)

这是我在Base Activity中用来更改背景的方法。我使用在代码中生成的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&lt; 4.3使用setCrossFadeEnabled(true)会导致不良的白化效果,所以我不得不切换到使用上面提到的@Roman Minenok ValueAnimator方法获得<4.3的纯色。

答案 7 :(得分:9)

最好的方法是使用 ValueAnimator ColorUtils.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.setColorBackground(ColorUtils.blendARGB(Color.parseColor("#FFFFFF")
                                    , Color.parseColor("#000000")
                                    , fractionAnim));
        }
});
valueAnimator.start();

答案 8 :(得分:6)

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

通过任何要更改其颜色的视图。

答案 9 :(得分:5)

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

for API&gt; 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();

答案 10 :(得分:4)

这是一个很好的功能,允许这样:

public static void animateBetweenColors(final View viewToAnimateItBackground, final int colorFrom, final int colorTo,
        final int durationInMs) {
    final ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
    colorAnimation.addUpdateListener(new AnimatorUpdateListener() {
        ColorDrawable colorDrawable = new ColorDrawable(colorFrom);

        @Override
        public void onAnimationUpdate(final ValueAnimator animator) {
            colorDrawable.setColor((Integer) animator.getAnimatedValue());
            viewToAnimateItBackground.setBackgroundDrawable(colorDrawable);
        }
    });
    if (durationInMs >= 0)
        colorAnimation.setDuration(durationInMs);
    colorAnimation.start();
}

答案 11 :(得分:2)

我发现Android源代码中ArgbEvaluator使用的实现在转换颜色方面做得最好。当使用HSV时,根据两种颜色,过渡对我来说是过多的色调。但是这种方法没有。

如果您只想设置动画效果,请按照here ValueAnimator.setCurrentFraction()使用ArgbEvaluatorValueAnimator

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及更高版本,在这种情况下,您可以使用ArgbEvaluator source code方法)。在API 22下面定位时,请在您自己的方法中包含https://jsfiddle.net/eh6pr7ee/2/中的代码,如下所示:

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

然后按照你的意愿使用它。

答案 12 :(得分:1)

基于XML的动画的文档非常糟糕。我搜索了大约几个小时,只是为了在按下时为按钮的背景色设置动画。可悲的是,动画只是一个属性而已:您可以在exitFadeDuration中使用selector:< / p>

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

答案 13 :(得分:1)

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

如果你想从当前背景颜色更改为新颜色,那么你可以使用这个

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

用法

myView.colorTransition(R.color.bg_color)

答案 14 :(得分:1)

你可以像这样使用 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()
}

答案 15 :(得分:0)

基于ademar111190's answer,我创建了此方法,该方法将使视图的背景颜色在任意两种颜色之间变化:

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

答案 16 :(得分:0)

您可以在API 11上方使用 ArgbEvaluatorCompat 类。

implementation 'com.google.android.material:material:1.0.0' 


ValueAnimator colorAnim = ValueAnimator.ofObject(new ArgbEvaluatorCompat(), startColor, endColor);
colorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mTargetColor = (int) animation.getAnimatedValue();
        }
    });
colorAnimation.start();