Androidでビューの背景色の変化をどのようにアニメートしますか?
例えば:
背景色が赤のビューがあります。ビューの背景色が青に変わります。どのようにして色を滑らかに変化させることができますか?
これがビューではできない場合は、代わりの方法があります。
私はこの問題に対する(かなり良い)解決策を考え出すことになった!
これを実現するには、 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では、このTransitionDrawableをAndroid:background
属性で参照します。
この時点で、次のようにしてコード内でコードの移行を開始できます。
TransitionDrawable transition = (TransitionDrawable) viewObj.getBackground();
transition.startTransition(transitionTime);
あるいは以下のように呼び出して遷移を逆に実行します。
transition.reverseTransition(transitionTime);
Property Animation APIを使用した別の解決策については、 Roman's answer を参照してください。この回答が最初に投稿された時点では利用できませんでした。
カラーアニメーションにはnew 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との後方互換性のために Nine Old Androids library Jake Whartonからを使用してください。
getColor
メソッドはAndroid Mでは推奨されていなかったので、2つの選択肢があります。
サポートライブラリを使用する場合は、getColor
の呼び出しを次のように置き換える必要があります。
ContextCompat.getColor(this, R.color.red);
サポートライブラリを使用しない場合は、getColor
の呼び出しを次のように置き換える必要があります。
getColor(R.color.red);
ビューの背景色の取得方法とターゲット色の取得方法に応じて、これを行う方法がいくつかあります。
最初の2つは Android Property Animation フレームワークを使います。
次の場合は Object Animator を使用してください。
argb
値として定義されています。view.setBackgroundColor()
によって設定されていましたオブジェクトアニメータは、定義されたdrawableがColorDrawable
のインスタンスでない限り、定義されたdrawableを置き換えるview.setBackgroundColor
を呼び出すことによって機能します。これは、ストロークや角のようなドロウアブルからの余分な背景プロパティが削除されることを意味します。
次の場合は、 Value Animator を使用してください。
次の場合は、 Transition drawable を使用してください。
DrawerLayoutを開いている間に実行できないトランジションドロアブルでパフォーマンス上の問題がいくつかありました。予期しない吃音が発生した場合は、同じバグが発生する可能性があります。
StateLists drawable または LayerLists drawable を使用する場合は、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();
XMightのようにAnimatorInflaterを使用してxmlからアニメーション定義をロードすることもできます Android objectAnimator animate backgroundColor of Layout
ビュー定義:
<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()
を呼び出すことでアニメーションを元に戻すことができます。
アニメーションを実行する方法は他にもありますが、これら3つがおそらく最も一般的です。私は通常ValueAnimatorを使います。
あなたはオブジェクトのアニメーターを作ることができます。例えば、私はtargetViewを持っています、そして私はあなたの背景色を変えたいです:
int colorFrom = Color.RED;
int colorTo = Color.GREEN;
int duration = 1000;
ObjectAnimator.ofObject(targetView, "backgroundColor", new ArgbEvaluator(), colorFrom, colorTo)
.setDuration(duration)
.start();
あなたがこのようなカラーアニメーションが欲しいならば、
このコードはあなたを助けます:
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();
これを実現するもう1つの簡単な方法は、AlphaAnimationを使用してフェードを実行することです。
最善の方法は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();
これは、背景を変更するために基本アクティビティで使用する方法です。私はコードで生成された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);
}
}
}
pdate:私が見つけた同じ問題に遭遇した場合、何らかの理由でsetCrossFadeEnabled(true)
を使ったAndroid <4.3では、@Romanを使った<4.3では純色に切り替える必要がありました上記のMinenok ValueAnimatorメソッド。
答えはいろいろな方法で与えられます。 ValueAnimator
のofArgb(startColor,endColor)
を使用することもできます。
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();
フォルダアニメータをresフォルダに追加します。 (名前はアニメーターにする必要があります)。アニメーターリソースファイルを追加します。例えば、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();
これを可能にするNice関数があります。
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();
}
私は、AndroidのソースコードでArgbEvaluator
が使用している実装が、色の遷移に最も適していることを発見しました。 HSVを使用する場合、2色によっては、移行が多すぎる色相を飛び越えていました。しかし、この方法は違います。
単純にアニメートしようとしている場合は、推奨されるようにArgbEvaluator
を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
source code にあるコードを独自のメソッドにラップします。
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))));
}
そしてあなたが望むならそれを使ってください。