Текстовая анимация цвета
Есть ли способ анимировать изменение цвета текста (от anycolor до белого)?
Единственный вариант, с которым я столкнулся, помещает два текстовых изображения (с одним и тем же текстом) в одном месте и затухает над верхней, поэтому нижний (имеющий белый цвет) станет видимым.
P.S. Я отказался от варианта 2 TextViews, так как он выглядел странно (края были негладкими, и, поскольку на экране было много таких элементов, это действительно задерживало прокрутку). То, что я сделал, было сумасшедшим взломом, который делает анимацию с использованием Thread и setTextColor (что также заставляет перерисовать текстовое изображение).
Поскольку мне нужно было всего 2 изменения цвета (от красного до белого и от зеленого до белого), я жестко закодировал значения и все цвета перехода между ними. Итак, вот как это выглядит:
public class BlinkingTextView extends TextView {
public BlinkingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void animateBlink(final boolean red) {
if (animator != null) {
animator.drop();
}
animator = new Animator(this, red);
animator.start();
}
public void clearBlinkAnimation() {
if (animator != null) {
animator.drop();
}
}
private Animator animator;
private final static class Animator extends Thread {
public Animator(final TextView textView, final boolean red) {
this.textView = textView;
if (red) {
SET_TO_USE = RED;
} else {
SET_TO_USE = GREEN;
}
}
private TextView textView;
private final int[] SET_TO_USE;
private final static int[] RED = {
-2142396,
-2008754,
-1874854,
-1740697,
-1540490,
-1405563,
-1205099,
-1004634,
-804170,
-669243,
-469036,
-334879,
-200979,
-67337,
-1
};
private final static int[] GREEN = {
-6959821,
-6565826,
-6106293,
-5646758,
-5055894,
-4530309,
-3939444,
-3283042,
-2692177,
-2166592,
-1575728,
-1116193,
-656660,
-262665,
-1
};
private boolean stop;
@Override
public void run() {
int i = 0;
while (i < 15) {
if (stop) break;
final int color = SET_TO_USE[i];
if (stop) break;
textView.post(new Runnable() {
@Override
public void run() {
if (!stop) {
textView.setTextColor(color);
}
}
});
if (stop) break;
i++;
if (stop) break;
try {
Thread.sleep(66);
} catch (InterruptedException e) {}
if (stop) break;
}
}
public void drop() {
stop = true;
}
}
}
Ответы
Ответ 1
Хотя я не нашел полностью отличный метод, я попытался использовать TextSwitcher (с анимацией затухания), чтобы создать эффект изменения цвета. A TextSwitcher
- это своего рода ViewSwitcher
, который буквально оживляет между двумя (внутренними) TextView
s. Вы вручную использовали ту же систему бессознательно?;) Он управляет немного больше процесса для вас, поэтому вам будет легче работать (особенно если вы хотите попробовать более привлекательные анимации). Я бы создал новый подкласс TextSwitcher
и некоторые методы, например. setColour()
, который может установить новый цвет, а затем вызвать анимацию. Затем код анимации можно перемещать за пределы основного приложения.
- убедитесь, что вы держите дескриптор двух
TextView
, которые помещаются в коммутатор
- измените цвет другого
TextView
и вызовите setText()
для анимации между ними
Если вы уже используете ViewSwitcher
, то я не думаю, что есть более простой способ реализовать это.
Ответ 2
Вы можете использовать новую анимацию свойств Api для цветовой анимации:
Integer colorFrom = getResources().getColor(R.color.red);
Integer colorTo = getResources().getColor(R.color.blue);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
textView.setTextColor((Integer)animator.getAnimatedValue());
}
});
colorAnimation.start();
Для обратной совместимости с Android 2.x используйте девятую библиотеку старых андроидов от Джейка Уортона.
Ответ 3
Самое простое решение - использовать объектные аниматоры:
ObjectAnimator colorAnim = ObjectAnimator.ofInt(yourTextView, "textColor",
Color.RED, Color.Green);
colorAnim.setEvaluator(new ArgbEvaluator());
colorAnim.start();
Ответ 4
Не нужно сохранять дескрипторы двух видов текста. Сначала добавьте анимацию fadeIn/fadeOut:
textSwitcher.setInAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_in));
textSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));
то
TextView currentTextView = (TextView)(textSwitcher.getNextView().equals(
textSwitcher.getChildAt(0)) ?
textSwitcher.getChildAt(1) : textSwitcher.getChildAt(0)
);
// setCurrentText() first to be the same as newText if you need to
textSwitcher.setTextColor(fadeOutColor);
((TextView) textSwitcher.getNextView()).setTextColor(Color.WHITE);
textSwitcher.setText(newText);
Просто реализовано так, как это было доказано, чтобы работать.
Ответ 5
лучший способ использовать 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();
textView.setTextColor(ColorUtils.blendARGB(Color.parseColor("#FFFFFF")
, Color.parseColor("#000000")
, fractionAnim));
}
});
valueAnimator.start();
Ответ 6
Я отказался от варианта 2 TextViews, так как он выглядел странно (края были негладкими, и, поскольку на экране было много таких элементов, это действительно зависело от прокрутки). То, что я сделал, было сумасшедшим взломом, который делает анимацию с использованием Thread и setTextColor (что также заставляет перерисовать текстовое изображение).
Поскольку мне нужно было всего 2 изменения цвета (от красного до белого и от зеленого до белого), я жестко закодировал значения и все цвета перехода между ними. Итак, вот как это выглядит:
public class BlinkingTextView extends TextView {
public BlinkingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void animateBlink(final boolean red) {
if (animator != null) {
animator.drop();
}
animator = new Animator(this, red);
animator.start();
}
public void clearBlinkAnimation() {
if (animator != null) {
animator.drop();
}
}
private Animator animator;
private final static class Animator extends Thread {
public Animator(final TextView textView, final boolean red) {
this.textView = textView;
if (red) {
SET_TO_USE = RED;
} else {
SET_TO_USE = GREEN;
}
}
private TextView textView;
private final int[] SET_TO_USE;
private final static int[] RED = {
-2142396,
-2008754,
-1874854,
-1740697,
-1540490,
-1405563,
-1205099,
-1004634,
-804170,
-669243,
-469036,
-334879,
-200979,
-67337,
-1
};
private final static int[] GREEN = {
-6959821,
-6565826,
-6106293,
-5646758,
-5055894,
-4530309,
-3939444,
-3283042,
-2692177,
-2166592,
-1575728,
-1116193,
-656660,
-262665,
-1
};
private boolean stop;
@Override
public void run() {
int i = 0;
while (i < 15) {
if (stop) break;
final int color = SET_TO_USE[i];
if (stop) break;
textView.post(new Runnable() {
@Override
public void run() {
if (!stop) {
textView.setTextColor(color);
}
}
});
if (stop) break;
i++;
if (stop) break;
try {
Thread.sleep(66);
} catch (InterruptedException e) {}
if (stop) break;
}
}
public void drop() {
stop = true;
}
}
}
Ответ 7
Проблема, которую я нашел с помощью valueAnimator, а также ObjectAnimator, заключается в том, что аниматор выполняет ряд случайных цветов, и переход не выглядит гладко. Я написал следующий код, который работал гладко. Надеюсь, это поможет и другому.
public static void changeTextColor(final TextView textView, int startColor, int endColor,
final long animDuration, final long animUnit){
if (textView == null) return;
final int startRed = Color.red(startColor);
final int startBlue = Color.blue(startColor);
final int startGreen = Color.green(startColor);
final int endRed = Color.red(endColor);
final int endBlue = Color.blue(endColor);
final int endGreen = Color.green(endColor);
new CountDownTimer(animDuration, animUnit){
//animDuration is the time in ms over which to run the animation
//animUnit is the time unit in ms, update color after each animUnit
@Override
public void onTick(long l) {
int red = (int) (endRed + (l * (startRed - endRed) / animDuration));
int blue = (int) (endBlue + (l * (startBlue - endBlue) / animDuration));
int green = (int) (endGreen + (l * (startGreen - endGreen) / animDuration));
textView.setTextColor(Color.rgb(red, green, blue));
}
@Override
public void onFinish() {
textView.setTextColor(Color.rgb(endRed, endGreen, endBlue));
}
}.start();
}
Ответ 8
Как упоминают другие, использование ObjectAnimator
решает для этого. Однако в существующих сообщениях я не видел, как установить продолжительность. Для меня изменение цвета произойдет немедленно.
В приведенном ниже решении показано:
void animateTextViewColors(TextView textView, Integer colorTo) {
final Property<TextView, Integer> property = new Property<TextView, Integer>(int.class, "textColor") {
@Override
public Integer get(TextView object) {
return object.getCurrentTextColor();
}
@Override
public void set(TextView object, Integer value) {
object.setTextColor(value);
}
};
final ObjectAnimator animator = ObjectAnimator.ofInt(textView, property, colorTo);
animator.setDuration(8533L);
animator.setEvaluator(new ArgbEvaluator());
animator.setInterpolator(new DecelerateInterpolator(2));
animator.start();
}
void oscillateDemo(final TextView textView) {
final int whiteColor = ContextCompat.getColor(TheApp.getAppContext(), R.color.white);
final int yellowColor = ContextCompat.getColor(TheApp.getAppContext(), R.color.yellow);
final int counter = 100;
Thread oscillateThread = new Thread() {
@Override
public void run() {
for (int i = 0; i < counter; i++) {
final int fadeToColor = (i % 2 == 0)
? yellowColor
: whiteColor;
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
animateTextViewColors(textView, fadeToColor);
}
});
try {
Thread.sleep(2450);
}
catch (InterruptedException iEx) {}
}
}
};
oscillateThread.start();
}