如何在Android上为视图的背景色变化设置动画?
例如:
我的背景色为红色。视图的背景色变为蓝色。如何在颜色之间进行平滑过渡?
如果无法使用视图完成此操作,将欢迎使用其他方法。
如何在Android上为视图的背景色变化设置动画?
例如:
我的背景色为红色。视图的背景色变为蓝色。如何在颜色之间进行平滑过渡?
如果无法使用视图完成此操作,将欢迎使用其他方法。
Answers:
我最终找到了解决这个问题的(相当不错的)解决方案!
您可以使用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的答案,该解决方案最初发布时尚不可用。
您可以将新的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);
ValueAnimator.ofArgb(colorFrom, colorTo)
看起来更重要,但可惜它是新的。
根据视图获取背景颜色的方式以及目标颜色的方式,可以通过几种不同的方法来实现。
前两个使用Android Property Animation框架。
在以下情况下使用对象动画器:
argb
xml文件中的值。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。
您可以使对象成为动画师。例如,我有一个targetView,我想更改您的背景色:
int colorFrom = Color.RED;
int colorTo = Color.GREEN;
int duration = 1000;
ObjectAnimator.ofObject(targetView, "backgroundColor", new ArgbEvaluator(), colorFrom, colorTo)
.setDuration(duration)
.start();
ofArgb(targetView, "backgroundColor", colorFrom, colorTo)
。它的实现是公正的ofInt(...).setEvaluator(new ArgbEvaluator())
。
如果您想要这样的彩色动画,
此代码将帮助您:
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();
anim.setRepeatCount(ValueAnimator.INFINITE);
现在不应该是Animation.INFINITE,现在还是一样,但是我们不能保证
最好的方法是使用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.setBackgroundColor(ColorUtils.blendARGB(Color.parseColor("#FFFFFF")
, Color.parseColor("#000000")
, fractionAnim));
}
});
valueAnimator.start();
实现此目的的另一种简便方法是使用AlphaAnimation执行淡入。
这是我在基本活动中用于更改背景的方法。我正在使用在代码中生成的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的纯色。
答案有很多方式。您还可以使用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();
有关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代码。
android:enterFadeDuration
;我的经验是,没有它,我的动画将无法第二次运行。
这是一个不错的功能,它可以实现以下目的:
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()
}
}
将文件夹动画器添加到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();
对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()
}
通过任何您想更改颜色的视图。
我发现ArgbEvaluator
Android源代码中使用的实现在过渡颜色方面表现最佳。使用HSV时,取决于两种颜色,过渡对我来说是通过太多的色调跳跃的。但是这种方法不是。
如果您只是想制作动画,请按照此处的建议使用ArgbEvaluator
with :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))));
}
并根据需要使用它。
基于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();
}