Androidでビューの背景色の変化をアニメーション化する


335

Androidでビューの背景色の変化をどのようにアニメーション化しますか?

例えば:

背景色が赤のビューがあります。ビューの背景色が青に変わります。色をスムーズに切り替えるにはどうすればよいですか?

ビューでこれを行うことができない場合は、代替案を歓迎します。


11
Androidのようなプラットフォームでは、色間のスムーズな移行が問題にならないはずです。たぶんそれのためにビューが構築されていません。問題はまだ残っています。
hpique 2010

回答:


374

私はこの問題の(かなり良い)解決策を見つけ出しました!

これを行うには、TransitionDrawableを使用できます。たとえば、ドローアブルフォルダーの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);

プロパティアニメーションAPIを使用する別のソリューションについては、この回答が最初に投稿された時点では利用できなかった、Romanの回答を参照してください。


3
ありがとうmxrider!これは質問に答えます。残念ながら、TransitionDrawableを背景として持つビューもアニメーション化する必要があるため、私にとっては機能しません。また、ビューアニメーションが背景の遷移をオーバーライドするようです。何か案は?
hpique 2010

6
アニメーションの開始後にTransitionDrawableを開始することで解決しました。
hpique

2
驚くばかり!うまくいきました。Androidを使用してxmlで実行できるクールなことがたくさんあります。それらの多くはドキュメントに埋もれており、私の意見では明らかではありません。
2010

4
まったくわかりません。色は動的なので、私の場合はxmlを使用していません。コードでTransitionDrawableを作成した場合も、ソリューションは機能します。
hpique 2010

2
主な欠点の1つは、アニメーションの完全なリスナーがないことです
Leo Droidcoder、

508

カラーアニメーションに新しいプロパティアニメーション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で廃止されたため、2つの選択肢があります。

  • サポートライブラリを使用する場合は、getColor呼び出しを次のものに置き換える必要があります。

    ContextCompat.getColor(this, R.color.red);
  • サポートライブラリを使用しない場合は、getColor呼び出しを次のものに置き換える必要があります。

    getColor(R.color.red);

2
プロパティアニメーションAPI(またはNineOldAndroid)を使用している場合は、「必須」のソリューション。非常にスムーズにアニメーション化します。
ドミトリーザイツェフ2014

1
このようにトランジションの期間を設定する方法はありますか?
iGio90 2014年

159
@ iGio90はい、あなたはそれを信じるつもりはありませんが、メソッド呼び出しsetDuration():)
Roman Minenok

6
ValueAnimator.ofArgb(colorFrom, colorTo)ポイントに見えるように見えるが、残念ながらそれは新しいです。
TWiStErRob 2016年

1
美しいソリューション!ありがとうございました。
スティーブフォリー

137

ビューの背景色の取得方法とターゲット色の取得方法に応じて、これを行う方法はいくつかあります。

最初の2つは、Androidプロパティアニメーションフレームワークを使用しています。

次の場合は、Object Animatorを使用します。

  • ビューの背景色は、 argbがxmlファイルの値ます。
  • ビューは以前に色が設定されています view.setBackgroundColor()
  • あなたのビューは、その背景色が描画可能に定義されていません脳卒中やコーナー半径などの余分なプロパティを定義します。
  • ビューの背景色がドローアブルで定義されており、ストロークやコーナー半径などの追加のプロパティを削除したい場合、追加のプロパティの削除はアニメーション化されないことに注意してください。

オブジェクトアニメーターview.setBackgroundColorは、のインスタンスでない限り、定義されたドローアブルを置き換えるを呼び出すことで機能しますColorDrawable。これは、ストロークやコーナーなどのドローアブルから余分な背景プロパティが削除されることを意味します。

次の場合はValue Animatorを使用します。

  • ビューの背景色は、ストロークやコーナーの半径などのプロパティも設定するドローアブルで定義されており、実行中に決定される新しい色に変更したい場合。

次の場合は、トランジションドローアブルを使用します。

  • ビューは、デプロイ前に定義された2つのドローアブルを切り替える必要があります。

私が解決できなかったDrawerLayoutを開いているときに実行されるTransitionドローアブルでパフォーマンスの問題が発生したため、予期しないスタッターが発生した場合は、同じバグが発生する可能性があります。

あなたが使用したい場合は、値アニメーターの例を変更する必要があります描画可能StateListsをLayerListsが描画可能なそれ以外の場合は、上でクラッシュします、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がAndroidオブジェクトで行うようにAnimatorInflaterを使用してxmlからアニメーション定義をロードすることもできますAnimator 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();

トランジションドローアブル

定義を表示:

<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を使用します。


コードでTransitionDrawableを定義して使用することは実際には可能ですが、何らかの理由で2回目には機能しません。変。
Android開発者

ビューにColorDrawableが設定されている場合でも、オブジェクトアニメーターを使用できます。これをローカル変数に保存してnullに設定し、アニメーションが終了したら、元のColorDrawableを元に戻します。
ミロシュČernilovský

55

オブジェクトアニメーターを作成できます。たとえば、targetViewがあり、背景色を変更したいとします。

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

2
API 21以降では、を使用できますofArgb(targetView, "backgroundColor", colorFrom, colorTo)。その実装はただofInt(...).setEvaluator(new ArgbEvaluator())です。
ypresto

20

このようなカラーアニメーションが必要な場合は、

ここに画像の説明を入力してください

このコードはあなたを助けるでしょう:

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

9
アニメーション変数が初期化されるときの部分はどこですか?
VoW

@VoW、それはValueAnimatorの単なるインスタンスです。
RBK

anim.setRepeatCount(ValueAnimator.INFINITE);今のところ、Animation.INFINITEではないはずです。同じですが、保証はありません
MikhailKrishtop

@MikhailKrishtop Animation.INFINITEの何が問題になっていますか?developer.android.com/reference/android/view/animation/...
RBK

14

最良の方法は、使用することです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();

12

これを実現する別の簡単な方法は、AlphaAnimationを使用してフェードを実行することです。

  1. ビューをViewGroupにする
  2. インデックス0に、match_parentレイアウト寸法で子ビューを追加します
  3. 子供にコンテナと同じ背景を与える
  4. コンテナーの背景をターゲットの色に変更します
  5. AlphaAnimationを使用して子をフェードアウトします。
  6. アニメーションが完了したときに子を削除します(AnimationListenerを使用)。

それはトリックです!よくやった 。。。
elyar abad

9

これは、基本アクティビティで背景を変更する方法です。私はコードで生成された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);
            }
        }
    }

更新:私が見つけた同じ問題にsetCrossFadeEnabled(true)誰かが遭遇した場合、何らかの理由でAndroid <4.3を使用すると望ましくないホワイトアウト効果が発生するため、上記の@Roman Minenok ValueAnimatorメソッドを使用して<4.3の無地に切り替える必要がありました。


これはまさに私が探していたものです。ありがとう!:)
cyph3r 2014

7

答えは多くの方法で与えられます。の使用も可能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();

7

これを可能にする優れた関数を次に示します。

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

これはローエンドのバージョンの電話をサポートしてい
ません

2
@KartheeksあなたはAndroid 10以下を意味しますか?その場合、「nineOldAndroids」ライブラリを簡単に使用してそれをサポートできます:nineoldandroids.com。構文はほとんど同じです。
Android開発者

下位バージョンの場合colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){@Override public void onAnimationUpdate(ValueAnimator animation){colorDrawable.setColor((Integer)animation.getAnimatedValue()); ViewCompat.setBackground(viewToAnimateItsBackground、colorDrawable);}}) ;
Mahbubur Ra​​hman Khan

6

XMLベースのアニメーションに関するドキュメントは恐ろしいものです。あなたが使用することができます:私はちょうど押したとき...悲しい事はアニメーションは1つの属性だけ離れているということであるボタンの背景色をアニメーション化するために時間を中心に検索した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コードは必要ありません。


あなたは私の日を救った。ありがとう。
フェデリコハイランド

1
すばらしい答えです。android:enterFadeDuration同様に必要な場合があることに注意してください。私の経験では、それがなければ、私のアニメーションは2回目には機能しませんでした。
文字列

5

フォルダーアニメーター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();

3

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

色を変更するビューを渡します。


2

ArgbEvaluatorAndroidのソースコードでによって使用されている実装が、色の遷移に最も適していることがわかりました。HSVを使用すると、2つの色に応じて、トランジションが私にとって非常に多くの色相を飛び越えていました。しかし、この方法はそうではありません。

単にアニメートする場合ArgbEvaluatorValueAnimatorここで提案されているようにwith を使用します

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

そして、あなたが好きなようにそれを使用してください。


0

ademar111190の回答に基づいて、ビューの背景色を2つの色の間でパルスするこのメソッドを作成しました。

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();
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.