Comment animer le changement de couleur d'arrière-plan d'une vue sur Android?
Par exemple:
J'ai une vue avec une couleur de fond rouge. La couleur d'arrière-plan de la vue devient bleue. Comment puis-je faire une transition en douceur entre les couleurs?
Si cela ne peut pas être fait avec des vues, une alternative sera la bienvenue.
J'ai fini par trouver une (très bonne) solution à ce problème!
Vous pouvez utiliser un TransitionDrawable pour accomplir cela. Par exemple, dans un fichier XML du dossier pouvant être dessiné, vous pouvez écrire quelque chose comme:
<?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>
Ensuite, dans votre XML pour la vue réelle, vous référenceriez cette TransitionDrawable dans l'attribut Android:background
.
À ce stade, vous pouvez lancer la transition dans votre code sur commande en procédant comme suit:
TransitionDrawable transition = (TransitionDrawable) viewObj.getBackground();
transition.startTransition(transitionTime);
Ou exécutez la transition en sens inverse en appelant:
transition.reverseTransition(transitionTime);
Voir réponse de Roman pour une autre solution utilisant l'API Property Animation, qui n'était pas disponible au moment où cette réponse a été publiée.
Vous pouvez utiliser new Property Animation Api pour l’animation couleur:
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();
Pour assurer la compatibilité ascendante avec Android 2.x, utilisez bibliothèque Nine Old Androids de Jake Wharton.
La méthode getColor
était obsolète dans Android M, vous avez donc deux choix:
Si vous utilisez la bibliothèque de support, vous devez remplacer les appels getColor
par:
ContextCompat.getColor(this, R.color.red);
si vous n'utilisez pas la bibliothèque de support, vous devez remplacer les appels getColor
par:
getColor(R.color.red);
En fonction de la couleur d'arrière-plan de votre vue et de la couleur cible, il existe différentes façons de procéder.
Les deux premiers utilisent le cadre Android Property Animation .
Utilisez un Object Animator si:
argb
dans un fichier XML.view.setBackgroundColor()
L’animateur d’objets fonctionne en appelant view.setBackgroundColor
qui remplace le dessin défini sauf s’il s’agit d’une instance de ColorDrawable
, ce qui est rarement le cas. Cela signifie que toutes les propriétés d'arrière-plan supplémentaires pouvant être dessinées, comme les traits ou les coins, seront supprimées.
Utilisez un Value Animator si:
Utilisez un Transition drawable si:
J'ai eu quelques problèmes de performances avec les tirables de Transition qui fonctionnent pendant que j'ouvre un DrawerLayout que je n'ai pas pu résoudre, donc si vous rencontrez un bégaiement inattendu, vous rencontrerez peut-être le même bogue que le mien.
Vous devrez modifier l'exemple de Value Animator si vous souhaitez utiliser un StateLists drawable ou un LayerLists drawable , sinon il se plantera sur la ligne final GradientDrawable background = (GradientDrawable) view.getBackground();
.
Voir la définition:
<View
Android:background="#FFFF0000"
Android:layout_width="50dp"
Android:layout_height="50dp"/>
Créez et utilisez une ObjectAnimator
comme celle-ci.
final ObjectAnimator backgroundColorAnimator = ObjectAnimator.ofObject(view,
"backgroundColor",
new ArgbEvaluator(),
0xFFFFFFFF,
0xff78c5f9);
backgroundColorAnimator.setDuration(300);
backgroundColorAnimator.start();
Vous pouvez également charger la définition d'animation à partir d'un fichier xml à l'aide d'un AnimatorInflater, comme XMight le fait dans Android objectAnimator animate backgroundColor of Layout
Voir la définition:
<View
Android:background="@drawable/example"
Android:layout_width="50dp"
Android:layout_height="50dp"/>
Définition tirable:
<?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>
Créez et utilisez un ValueAnimator comme ceci:
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();
Voir la définition:
<View
Android:background="@drawable/example"
Android:layout_width="50dp"
Android:layout_height="50dp"/>
Définition tirable:
<?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>
Utilisez le TransitionDrawable comme ceci:
final TransitionDrawable background = (TransitionDrawable) view.getBackground();
background.startTransition(300);
Vous pouvez inverser les animations en appelant .reverse()
sur l'instance d'animation.
Il y a d'autres façons de faire des animations mais ces trois sont probablement les plus courantes. J'utilise généralement un ValueAnimator.
Vous pouvez faire un animateur d'objet. Par exemple, j'ai un targetView et je veux changer votre couleur de fond:
int colorFrom = Color.RED;
int colorTo = Color.GREEN;
int duration = 1000;
ObjectAnimator.ofObject(targetView, "backgroundColor", new ArgbEvaluator(), colorFrom, colorTo)
.setDuration(duration)
.start();
Si vous voulez une animation couleur comme celle-ci,
ce code vous aidera:
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();
le meilleur moyen consiste à utiliser ValueAnimator et 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();
Un autre moyen simple d'y parvenir consiste à effectuer un fondu à l'aide d'AlphaAnimation.
C'est la méthode que j'utilise dans une activité de base pour changer de fond. J'utilise GradientDrawables généré dans le code, mais pourrait être adapté en conséquence.
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);
}
}
}
pdate: Si quelqu'un rencontre le même problème que j'ai trouvé, pour quelque raison que ce soit sur Android <4.3, en utilisant setCrossFadeEnabled(true)
, un effet de blanc indésirable m'a obligé à changer en couleur unie pour <4,3 en utilisant la méthode @Roman Minenok ValueAnimator indiquée ci-dessus.
La réponse est donnée à bien des égards. Vous pouvez également utiliser ofArgb(startColor,endColor)
sur ValueAnimator
.
pour 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();
Voici une fonction intéressante qui permet ceci:
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();
}
ajouter un dossier animateur dans le dossier res. (le nom doit être animateur). Ajoutez un fichier de ressources d'animateur. Par exemple 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>
Dans le fichier Activity Java, appelez-le.
View v = getWindow().getDecorView().findViewById(Android.R.id.content);
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.fade);
set.setTarget(v);
set.start();
J'ai constaté que l'implémentation utilisée par ArgbEvaluator
dans le code source Android fonctionne mieux dans la transition des couleurs. Lorsque vous utilisez le HSV, selon les deux couleurs, la transition sautait trop de teintes pour moi. Mais cette méthode ne fonctionne pas.
Si vous essayez simplement d’animer, utilisez ArgbEvaluator
avec ValueAnimator
comme suggéré ici :
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();
Toutefois, si vous êtes comme moi et souhaitez associer votre transition à un geste de l'utilisateur ou à une autre valeur transmise à partir d'une entrée, le paramètre ValueAnimator
ne vous sera pas d'une grande aide (à moins que vous ne cibliez l'API 22 ou une version ultérieure, auquel cas vous pouvez utiliser la méthode ValueAnimator.setCurrentFraction()
). Lorsque vous ciblez sous API 22, encapsulez le code trouvé dans ArgbEvaluator
code source dans votre propre méthode, comme indiqué ci-dessous:
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))));
}
Et utilisez-le comme vous le souhaitez.