คุณเคลื่อนไหวการเปลี่ยนสีพื้นหลังของมุมมองบน Android ได้อย่างไร
ตัวอย่างเช่น:
ฉันมีมุมมองที่มีสีพื้นหลังสีแดง สีพื้นหลังของมุมมองเปลี่ยนเป็นสีน้ำเงิน ฉันจะเปลี่ยนระหว่างสีได้อย่างราบรื่นได้อย่างไร
หากไม่สามารถทำได้ด้วยมุมมองทางเลือกจะยินดีต้อนรับ
คุณเคลื่อนไหวการเปลี่ยนสีพื้นหลังของมุมมองบน Android ได้อย่างไร
ตัวอย่างเช่น:
ฉันมีมุมมองที่มีสีพื้นหลังสีแดง สีพื้นหลังของมุมมองเปลี่ยนเป็นสีน้ำเงิน ฉันจะเปลี่ยนระหว่างสีได้อย่างราบรื่นได้อย่างไร
หากไม่สามารถทำได้ด้วยมุมมองทางเลือกจะยินดีต้อนรับ
คำตอบ:
ฉันพบวิธีแก้ปัญหา (ดีมาก) สำหรับปัญหานี้!
คุณสามารถใช้TransitionDrawableเพื่อทำสิ่งนี้ให้สำเร็จ ตัวอย่างเช่นในไฟล์ XML ในโฟลเดอร์ drawable คุณสามารถเขียนสิ่งที่ชอบ:
<?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 ซึ่งไม่สามารถใช้ได้ในขณะที่โพสต์คำตอบนี้ไว้
คุณสามารถใช้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จาก Jake Wharton
getColor
วิธีการได้รับการคัดค้านใน Android M เพื่อให้คุณมีสองตัวเลือก:
หากคุณใช้ไลบรารีการสนับสนุนคุณจะต้องแทนที่การgetColor
โทรด้วย:
ContextCompat.getColor(this, R.color.red);
หากคุณไม่ได้ใช้ไลบรารีการสนับสนุนคุณจะต้องแทนที่การgetColor
โทรด้วย:
getColor(R.color.red);
ValueAnimator.ofArgb(colorFrom, colorTo)
มองไปที่จุดมากขึ้น แต่น่าเสียดายที่มันใหม่
ขึ้นอยู่กับว่ามุมมองของคุณใช้สีพื้นหลังอย่างไรและคุณได้สีเป้าหมายอย่างไรมีหลายวิธีในการทำเช่นนี้
สองคนแรกใช้เฟรมเวิร์กภาพเคลื่อนไหวคุณสมบัติของ Android
ใช้Object Animatorถ้า:
argb
ค่าในไฟล์ xmlview.setBackgroundColor()
อนิเมชั่น Object ทำงานโดยการเรียกview.setBackgroundColor
ซึ่งแทนที่ drawable ที่กำหนดไว้ยกเว้นว่ามันเป็นตัวอย่างของ a ColorDrawable
ซึ่งไม่ค่อยเป็น ซึ่งหมายความว่าคุณสมบัติพื้นหลังพิเศษใด ๆ จาก drawable เช่นโรคหลอดเลือดสมองหรือมุมจะถูกลบออก
ใช้Animator ที่คุ้มค่าหาก:
ใช้การเปลี่ยนผ่าน drawableถ้า:
ฉันมีปัญหาด้านประสิทธิภาพบางอย่างเกี่ยวกับการเปลี่ยนผ่าน drawable ที่ทำงานในขณะที่ฉันกำลังเปิด DrawerLayout ที่ฉันไม่สามารถแก้ไขได้ดังนั้นหากคุณพบการพูดติดอ่างที่ไม่คาดคิดคุณอาจพบข้อผิดพลาดแบบเดียวกับที่ฉันมี
คุณจะต้องแก้ไขตัวอย่างของแอนิเมชั่นค่าหากคุณต้องการใช้StateLists drawableหรือLayerLists drawableมิฉะนั้นจะเกิดความผิดพลาดใน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();
คุณยังสามารถโหลดคำจำกัดความแอนิเมชั่นจาก xml โดยใช้ AnimatorInflater เช่น XMight ใน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()
ใช้อินสแตนซ์ภาพเคลื่อนไหว
มีวิธีอื่นในการทำแอนิเมชั่น แต่ทั้งสามอาจเป็นเรื่องธรรมดาที่สุด ฉันมักใช้ 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);
}
}
}
อัปเดต:ในกรณีที่ทุกคนพบปัญหาเดียวกันฉันพบว่าด้วยเหตุผลบางอย่างบน Android <4.3 การใช้setCrossFadeEnabled(true)
ทำให้เกิดผลสีขาวที่ไม่พึงประสงค์ดังนั้นฉันจึงต้องเปลี่ยนเป็นสีทึบสำหรับ <4.3 โดยใช้วิธี @Roman Minenok ValueAnimator
คำตอบมีให้หลายวิธี นอกจากนี้คุณยังสามารถใช้ของ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();
เอกสารเกี่ยวกับภาพเคลื่อนไหวที่ขับเคลื่อนด้วย XML นั้นน่ากลัวมาก ฉันค้นหาไปหลายชั่วโมงเพื่อทำให้สีพื้นหลังของปุ่มเคลื่อนไหวเมื่อกด ... สิ่งที่น่าเศร้าคืออนิเมชั่นอยู่ห่างออกไปเพียงหนึ่งคุณลักษณะ: คุณสามารถใช้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
เช่นกัน ประสบการณ์ของฉันคือการที่ภาพเคลื่อนไหวของฉันไม่ทำงานครั้งที่สอง
นี่เป็นฟังก์ชั่นที่ดีที่ทำให้:
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();
}
}
และใน Kotlin:
@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()
}
}
เพิ่มแอนิเมเตอร์โฟลเดอร์ลงในโฟลเดอร์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>
ภายในไฟล์ 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 ขึ้นอยู่กับสองสีการเปลี่ยนแปลงก็กระโดดผ่านเฉดสีมากเกินไปสำหรับฉัน แต่วิธีนี้ไม่ได้
หากคุณกำลังพยายามจะเคลื่อนไหวเพียงใช้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
ซอร์สโค้ดในวิธีการของคุณเองดังที่แสดงด้านล่าง:
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ฉันได้สร้างวิธีการนี้ซึ่งจะทำให้สีพื้นหลังของมุมมองระหว่างสองสี:
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();
}