Androidでビューの背景色の変化をどのようにアニメーション化しますか?
例えば:
背景色が赤のビューがあります。ビューの背景色が青に変わります。色をスムーズに切り替えるにはどうすればよいですか?
ビューでこれを行うことができない場合は、代替案を歓迎します。
Androidでビューの背景色の変化をどのようにアニメーション化しますか?
例えば:
背景色が赤のビューがあります。ビューの背景色が青に変わります。色をスムーズに切り替えるにはどうすればよいですか?
ビューでこれを行うことができない場合は、代替案を歓迎します。
回答:
私はこの問題の(かなり良い)解決策を見つけ出しました!
これを行うには、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の回答を参照してください。
カラーアニメーションに新しいプロパティアニメーション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);
ValueAnimator.ofArgb(colorFrom, colorTo)
ポイントに見えるように見えるが、残念ながらそれは新しいです。
ビューの背景色の取得方法とターゲット色の取得方法に応じて、これを行う方法はいくつかあります。
最初の2つは、Androidプロパティアニメーションフレームワークを使用しています。
次の場合は、Object Animatorを使用します。
argb
がxmlファイルの値ます。view.setBackgroundColor()
オブジェクトアニメーターview.setBackgroundColor
は、のインスタンスでない限り、定義されたドローアブルを置き換えるを呼び出すことで機能しますColorDrawable
。これは、ストロークやコーナーなどのドローアブルから余分な背景プロパティが削除されることを意味します。
次の場合はValue Animatorを使用します。
次の場合は、トランジションドローアブルを使用します。
私が解決できなかった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
定義を表示:
<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();
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);
}
}
}
更新:私が見つけた同じ問題にsetCrossFadeEnabled(true)
誰かが遭遇した場合、何らかの理由でAndroid <4.3を使用すると望ましくないホワイトアウト効果が発生するため、上記の@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();
これを可能にする優れた関数を次に示します。
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()
}
}
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コードは必要ありません。
android:enterFadeDuration
同様に必要な場合があることに注意してください。私の経験では、それがなければ、私のアニメーションは2回目には機能しませんでした。
フォルダーアニメーターを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を使用すると、2つの色に応じて、トランジションが私にとって非常に多くの色相を飛び越えていました。しかし、この方法はそうではありません。
単にアニメートする場合ArgbEvaluator
はValueAnimator
、ここで提案されているように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))));
}
そして、あなたが好きなようにそれを使用してください。
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();
}