可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
How do you animate the change of background color of a view on Android?
For example:
I have a view with a red background color. The background color of the view changes to blue. How can I do a smooth transition between colors?
If this can't be done with views, an alternative will be welcome.
回答1:
I ended up figuring out a (pretty good) solution for this problem!
You can use a TransitionDrawable to accomplish this. For example, in an XML file in the drawable folder you could write something like:
Then, in your XML for the actual View you would reference this TransitionDrawable in the android:background
attribute.
At this point you can initiate the transition in your code on-command by doing:
TransitionDrawable transition = (TransitionDrawable) viewObj.getBackground(); transition.startTransition(transitionTime);
Or run the transition in reverse by calling:
transition.reverseTransition(transitionTime);
See Roman's answer for another solution using the Property Animation API, which wasn't available at the time this answer was originally posted.
回答2:
You can use new Property Animation Api for color animation:
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();
For backward compatibility with Android 2.x use Nine Old Androids library from Jake Wharton.
The getColor
method was deprecated in Android M, so you have two choices:
If you use the support library, you need to replace the getColor
calls with:
ContextCompat.getColor(this, R.color.red);
if you don't use the support library, you need to replace the getColor
calls with:
getColor(R.color.red);
回答3:
Depending on how your view gets its background color and how you get your target color there are several different ways to do this.
The first two uses the Android Property Animation framework.
Use a Object Animator if:
- Your view have its background color defined as a
argb
value in a xml file. - Your view have previously had its color set by
view.setBackgroundColor()
- Your view have its background color defined in a drawable that DOES NOT defines any extra properties like stroke or corner radiuses.
- Your view have its background color defined in a drawable and you want to remove any extra properties like stroke or corner radiuses, keep in mind that the removal of the extra properties will not animated.
The object animator works by calling view.setBackgroundColor
which replaces the defined drawable unless is it an instance of a ColorDrawable
, which it rarely is. This means that any extra background properties from a drawable like stroke or corners will be removed.
Use a Value Animator if:
- Your view have its background color defined in a drawable that also sets properties like the stroke or corner radiuses AND you want to change it to a new color that is decided while running.
Use a Transition drawable if:
- Your view should switch between two drawable that have been defined before deployment.
I have had some performance issues with Transition drawables that runs while I am opening a DrawerLayout that I haven't been able to solve, so if you encounter any unexpected stuttering you might have run into the same bug as I have.
You will have to modify the Value Animator example if you want to use a StateLists drawable or a LayerLists drawable, otherwise it will crash on the final GradientDrawable background = (GradientDrawable) view.getBackground();
line.
Object Animator:
View definition:
Create and use a ObjectAnimator
like this.
final ObjectAnimator backgroundColorAnimator = ObjectAnimator.ofObject(view, "backgroundColor", new ArgbEvaluator(), 0xFFFFFFFF, 0xff78c5f9); backgroundColorAnimator.setDuration(300); backgroundColorAnimator.start();
You can also load the animation definition from a xml using a AnimatorInflater like XMight does in Android objectAnimator animate backgroundColor of Layout
Value Animator:
View definition:
Drawable definition:
Create and use a ValueAnimator like this:
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 definition:
Drawable definition:
Use the TransitionDrawable like this:
final TransitionDrawable background = (TransitionDrawable) view.getBackground(); background.startTransition(300);
You can reverse the animations by calling .reverse()
on the animation instance.
There are some other ways to do animations but these three is probably the most common. I generally use a ValueAnimator.
回答4:
You can make an object animator. For example, I have a targetView and I want to change your background color:
int colorFrom = Color.RED; int colorTo = Color.GREEN; int duration = 1000; ObjectAnimator.ofObject(targetView, "backgroundColor", new ArgbEvaluator(), colorFrom, colorTo) .setDuration(duration) .start();
回答5:
If you want color animation like this,
this code will help you:
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();
回答6:
Another easy way to achieve this is to perform a fade using AlphaAnimation.
- Make your view a ViewGroup
- Add a child view to it at index 0, with match_parent layout dimensions
- Give your child the same background as the container
- Change to background of the container to the target color
- Fade out the child using AlphaAnimation.
- Remove the child when the animation is complete (using an AnimationListener)
回答7:
This is the method I use in a Base Activity to change background. I'm using GradientDrawables generated in code, but could be adapted to suit.
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
update: In case anyone runs in to same issue I found, for some reason on Android setCrossFadeEnabled(true) cause a undesirable white out effect so I had to switch to a solid colour for
回答8:
Here's a nice function that allows this:
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(); }
回答9:
I've found that the implementation used by ArgbEvaluator
in the Android source code does best job in transitioning colors. When using HSV, depending on the two colors, the transition was jumping through too many hues for me. But this method's doesn't.
If you are trying to simply animate, use ArgbEvaluator
with ValueAnimator
as suggested here:
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();
However, if you are like me and want to tie your transition with some user gesture or other value passed from an input, the ValueAnimator
is not of much help (unless your are targeting for API 22 and above, in which case you can use the ValueAnimator.setCurrentFraction()
method). When targeting below API 22, wrap the code found in ArgbEvaluator
source code in your own method, as shown below:
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)))
And use it however you wish.
回答10:
best way use ValueAnimator and 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();
回答11:
Answer is given in many ways. You can also use ofArgb(startColor,endColor)
of ValueAnimator
.
for 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();