Change actionbar alpha during scroll event - android

I try to create a fade alpha on my actionbar during a scroll event of my main ScrollView :
I tried this :
//Active Overlay for ActionBar before set my content in the activity
getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
//create a new Drawable for the AB background
final ColorDrawable newColor = new ColorDrawable(getResources().getColor(R.color.primaryColor));
newColor.setAlpha(0);
getActionBar().setBackgroundDrawable(newColor);
//create a OnScrollListener to get ScrollY position
final ScrollView mainScrollView = (ScrollView) findViewById(R.id.place_detail_scrollView);
mainScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
final int scrollY = mainScrollView.getScrollY();
final int boundY = 300;
final float ratio = (float) (scrollY/boundY) ;
newColor.setAlpha((int)(ratio*255));
}
});
In theory, my actionbar will fade its alpha between position 0 and 300 of the ScrollView. Unfortunately, my AB still transparent everytime... Any idea ?

I found the problem, I use a pre Jelly Bean device so there's a workaround for this issue.
In fact, with pre-JELLY_BEAN_MR1 device, we have to attach the following Callback in the onCreate(Bundle) method for the Drawable :
private Drawable.Callback mDrawableCallback = new Drawable.Callback() {
#Override
public void invalidateDrawable(Drawable who) {
getActionBar().setBackgroundDrawable(who);
}
#Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
}
#Override
public void unscheduleDrawable(Drawable who, Runnable what) {
}
};
then set the callback
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
mActionBarBackgroundDrawable.setCallback(mDrawableCallback);
}
And that's all, thank you to Cyril Mottier for this !

Related

How to set smoothly animation to progressBar in android

In my project I want use ProgressBar and I want set smoothly countdown animation.
I write below codes for smoothly animation and when set 1000ms (1s) for duration show smoothly animation, but I want set 10000ms (10s) for duration.
When set 10000ms (10s) for duration not smoothly animation and show Fragmentary countdown.
But I want set 10000ms for duration and show smoothly countdown.
public class SimpleFrag extends Fragment {
TextView toolbar_title;
RelativeLayout toolbar;
private ProgressBar progressBar;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_simple, container, false);
ButterKnife.bind(this, view);
toolbar_title = getActivity().findViewById(R.id.toolbar_title);
toolbar = getActivity().findViewById(R.id.toolbar);
progressBar = view.findViewById(R.id.progress);
return view;
}
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#SuppressLint("ObjectAnimatorBinding")
#Override
public void run() {
ProgressBarAnimation mProgressAnimation = new ProgressBarAnimation(progressBar, 79, 0);
mProgressAnimation.setDuration(10000);
progressBar.startAnimation(mProgressAnimation);
}
}, 50);
}
}
public class ProgressBarAnimation extends Animation {
private ProgressBar progressBar;
private float from;
private float to;
public ProgressBarAnimation(ProgressBar progressBar, float from, float to) {
super();
this.progressBar = progressBar;
this.from = from;
this.to = to;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
float value = from + (to - from) * interpolatedTime;
progressBar.setProgress((int) value);
}
}
}
How can I it? please help me . Thanks all <3
Take what you have now, and delete your setUserVisibleHint() method and your ProgressBarAnimation class. Add this:
private void setUpObserver() {
progressBar.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
startAnimation();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
progressBar.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
else {
progressBar.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
});
}
private void startAnimation() {
int width = progressBar.getWidth();
progressBar.setMax(width);
ValueAnimator animator = ValueAnimator.ofInt(0, width);
animator.setInterpolator(new LinearInterpolator());
animator.setStartDelay(0);
animator.setDuration(10_000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int value = (int) valueAnimator.getAnimatedValue();
progressBar.setProgress(value);
}
});
animator.start();
}
Then, inside your onCreateView() method, call setUpObserver() right before you return view;
The setUpObserver() method uses an OnGlobalLayoutListener to make sure that the system waits until the ProgressBar is measured an laid out before starting the animation.
The startAnimation() method is what takes care of actually setting up and running the animation. You can modify the values passed to setStartDelay() and setDuration() as you see fit.
The trick to this solution is making sure that the maximum value for the progress bar is equal to its width, meaning that each increment of "progress" is equal to one pixel on the screen. The android framework animation takes care of making sure everything runs as smoothly as possible.
Edit
If you want to be able to control the start/end points for the animation (rather than just go from empty to full), make these changes:
Change the declaration of startAnimation() to this:
private void startAnimation(float startPercent, float endPercent)
Delete this line from inside startAnimation()
ValueAnimator animator = ValueAnimator.ofInt(0, width);
and add these lines instead:
int start = (int) (startPercent * width);
int end = (int) (endPercent * width);
ValueAnimator animator = ValueAnimator.ofInt(start, end);
Finally, call startAnimation() by passing in fractional percentages:
startAnimation(0.79f, 0.10f); // will animate from 79% to 10%

How to blur the background image of the main layout in android?

I just want to make the background image to look blur(like defocus),I used alpha but it was not only setting alpha to my background image but also to the whole content...Is there any way that I can set blur effect only to my background image!!!..
need help thanks in advance!!..
Please use below tutorial for blur background
NavigationDrawer :
https://github.com/charbgr/BlurNavigationDrawer
Fragment:
https://github.com/tvbarthel/BlurDialogFragment
Image : If you want to blur an image in layout :
https://github.com/kikoso/android-stackblur
Layout:
https://github.com/PomepuyN/BlurEffectForAndroidDesign
public class MainActivity extends Activity {
private static final String BLURRED_IMG_PATH = "blurred_image.png";
private static final int TOP_HEIGHT = 700;
private ListView mList;
private ImageView mBlurredImage;
private View headerView;
private ImageView mNormalImage;
private ScrollableImageView mBlurredImageHeader;
private Switch mSwitch;
private float alpha;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_main);
// Get the screen width
final int screenWidth = ImageUtils.getScreenWidth(this);
// Find the view
mBlurredImage = (ImageView) findViewById(R.id.blurred_image);
mNormalImage = (ImageView) findViewById(R.id.normal_image);
mBlurredImageHeader = (ScrollableImageView) findViewById(R.id.blurred_image_header);
mSwitch = (Switch) findViewById(R.id.background_switch);
mList = (ListView) findViewById(R.id.list);
// prepare the header ScrollableImageView
mBlurredImageHeader.setScreenWidth(screenWidth);
// Action for the switch
mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
mBlurredImage.setAlpha(alpha);
} else {
mBlurredImage.setAlpha(0f);
}
}
});
// Try to find the blurred image
final File blurredImage = new File(getFilesDir() + BLURRED_IMG_PATH);
if (!blurredImage.exists()) {
// launch the progressbar in ActionBar
setProgressBarIndeterminateVisibility(true);
new Thread(new Runnable() {
#Override
public void run() {
// No image found => let's generate it!
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.image, options);
Bitmap newImg = Blur.fastblur(MainActivity.this, image, 12);
ImageUtils.storeImage(newImg, blurredImage);
runOnUiThread(new Runnable() {
#Override
public void run() {
updateView(screenWidth);
// And finally stop the progressbar
setProgressBarIndeterminateVisibility(false);
}
});
}
}).start();
} else {
// The image has been found. Let's update the view
updateView(screenWidth);
}
String[] strings = getResources().getStringArray(R.array.list_content);
// Prepare the header view for our list
headerView = new View(this);
headerView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, TOP_HEIGHT));
mList.addHeaderView(headerView);
mList.setAdapter(new ArrayAdapter<String>(this, R.layout.list_item, strings));
mList.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
/**
* Listen to the list scroll. This is where magic happens ;)
*/
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// Calculate the ratio between the scroll amount and the list
// header weight to determinate the top picture alpha
alpha = (float) -headerView.getTop() / (float) TOP_HEIGHT;
// Apply a ceil
if (alpha > 1) {
alpha = 1;
}
// Apply on the ImageView if needed
if (mSwitch.isChecked()) {
mBlurredImage.setAlpha(alpha);
}
// Parallax effect : we apply half the scroll amount to our
// three views
mBlurredImage.setTop(headerView.getTop() / 2);
mNormalImage.setTop(headerView.getTop() / 2);
mBlurredImageHeader.handleScroll(headerView.getTop() / 2);
}
});
}
private void updateView(final int screenWidth) {
Bitmap bmpBlurred = BitmapFactory.decodeFile(getFilesDir() + BLURRED_IMG_PATH);
bmpBlurred = Bitmap.createScaledBitmap(bmpBlurred, screenWidth, (int) (bmpBlurred.getHeight()
* ((float) screenWidth) / (float) bmpBlurred.getWidth()), false);
mBlurredImage.setImageBitmap(bmpBlurred);
mBlurredImageHeader.setoriginalImage(bmpBlurred);
}
}
Kotlin code, use view effect Library :
1- Add library in build.gradle:
implementation 'com.github.mirrajabi:view-effects:e355a1bac4'
2- Blure the background of root view or view, here Constraint Layout blured by 20%
ViewFilter.getInstance(this)
.setRenderer( BlurRenderer(20))
.applyFilterOnView( root_constraintLayout,
root_constraintLayout )
my github repository for blur background : link

Error while trying to create circular reveal: IllegalStateException: cannot start this animation on a detached view

So, I'm experimenting trying to create a circular reveal on API level 21 on a TextView but I keep getting this error. At first I thought it had something to do with the lifecycle of the fragment I was attempting it but then I just tried the same thing in an activity and it still wouldn't work.
Here's the code:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window w = getWindow();
w.setFlags(
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
w.setStatusBarColor(Color.parseColor("#0277bd"));
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.text);
int a = (tv.getLeft() + tv.getRight()) / 2;
int b = (tv.getTop() + tv.getBottom()) / 2;
int radius = tv.getWidth();
Animator anim = ViewAnimationUtils.createCircularReveal(tv, a, b, 0, radius);
anim.start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return super.onCreateOptionsMenu(menu);
}
}
It's still early days so I can't really find any answers about this. Any ideas?
You're getting the error because the view you passed in hasn't been measured and laid out on the screen yet. ViewAnimationUtils.createCircularReveal needs the target view to be measured to calculate the animation. You'll also find that your variables a and b are always 0.
If you want to experiment, create the animation and start it within a button click listener. Here's an example using your code:
Button button = (Button) findViewById(R.id.your_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView tv = (TextView) findViewById(R.id.text);
int a = (tv.getLeft() + tv.getRight()) / 2;
int b = (tv.getTop() + tv.getBottom()) / 2;
int radius = tv.getWidth();
Animator anim = ViewAnimationUtils.createCircularReveal(tv, a, b, 0, radius);
anim.start();
}
});
You can use Runnable to do the animation. The Runnable will run after the view's creation. No need to post delay.
view.post(new Runnable()
{
#Override
public void run(){
//create your anim here
}
});
Or you can do this.
tv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
tv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
tv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
Animator anim = ViewAnimationUtils.createCircularReveal(tv, a, b, 0, radius);
anim.start();
}
});
Adding GlobalLayoutListener to wait for the view to be inflated worked for me.
Or you can do this.
tv.postDelayed(new Runnable() {
#Override
public void run() {
//start your animation here
}
}, 1000);

ProgressBar causing constant onDraw calls for all the UI

I have an activity which has a ProgressBar. This bar is used to show the elapsed time on the game level.
I'm updating this bar and a TextView with a CountdownTimer, called every 100ms. The problem is that every time I call setProgress, it seems to be causing an invalidate() that makes my whole UI to be redrawn. If I delete the line where the ProgressBar get updated everything works fine, even setText for the TextView that show the time left.
This is a problem for me because I also have a custom view which needs to be redrawn only when I need it, or at least a few times but not constantly because it'll affect performance.
This is a piece of my code:
private CountDownTimer timer;
private long ttime;
private long ctime;
private ProgressBar bar;
private TextView clock;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
startTimer(500);
...
}
#Override
protected void onResume() {
super.onResume();
if(!checkFlags()){
startTimer(500);
}
}
#Override
protected void onPause() {
super.onPause();
if(!checkFlags()){
timer.cancel();
}
}
private void startTimer(long delay){
timer = new CountDownTimer(ctime,100){
public void onTick(long millisUntilFinished){
ctime = millisUntilFinished;
clock.setText(formatTime(millisUntilFinished));
bar.setProgress((int) (1000 - ((ctime * 1000)/ttime)));
}
public void onFinish(){
clock.setText("00:00");
gameOver(false);
}
};
if(delay > 0){
Handler handler = new Handler();
handler.postDelayed(new Runnable(){
public void run(){
timer.start();
}
},delay);
}else{
timer.start();
}
}
How could I prevent the ProgressBar to cause this onDraw calls for every element of the UI?
According to 'sources/android-18/android/widget/ProgressBar.java' in Android SDK the call of setProgress() will result in the call of invalidate().
private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
boolean callBackToApp) {
float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
final Drawable d = mCurrentDrawable;
if (d != null) {
Drawable progressDrawable = null;
if (d instanceof LayerDrawable) {
progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id);
if (progressDrawable != null && canResolveLayoutDirection()) {
progressDrawable.setLayoutDirection(getLayoutDirection());
}
}
final int level = (int) (scale * MAX_LEVEL);
(progressDrawable != null ? progressDrawable : d).setLevel(level);
} else {
>>> invalidate();
}
if (callBackToApp && id == R.id.progress) {
onProgressRefresh(scale, fromUser);
}
}
Try to use setProgressDrawable(). It seems that invalidate() is not called in that case.

Text color animation

Is there a way to animate a text color change (from anycolor to white)?
The only variant I came up with, is placing two textviews (with the same text) in one place, and fading the top one, so the bottom one (that has a white color) will become visible.
P.S. I scrapped the variant of the 2 TextViews since it looked weird (edges weren't smooth and, since I have a lot of such elements on the screen it was really lagging the scrolling). What I did, was a crazy hack that does the animation with the use of a Thread and setTextColor (that also forces redraw of a textview).
Since I needed only 2 color changes (from red to white, and from green to white) I hardcoded the values and all of the transition colors between them. So here's how it looks:
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;
}
}
}
You can use new Property Animation Api for color animation:
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();
For backward compatability with Android 2.x use Nine Old Androids library from Jake Wharton.
The Easiest solution will be to use Object Animators :
ObjectAnimator colorAnim = ObjectAnimator.ofInt(yourTextView, "textColor",
Color.RED, Color.GREEN);
colorAnim.setEvaluator(new ArgbEvaluator());
colorAnim.start();
No need to keep handles to the two text views. First add the fadeIn/fadeOut animations:
textSwitcher.setInAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_in));
textSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));
then:
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);
Just implemented it like this so proven to work.
best way use ValueAnimator and 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();
Although I haven't found a totally distinct method, I have tried to use a TextSwitcher (with the fade animation) to create the colour-change effect. A TextSwitcher is a kind of ViewSwitcher which literally animates between two (internal) TextViews. Did you manually implement the same system unknowingly? ;) It manages a bit more of the process for you, so you may find it easier to work with (especially if you want to try more involved animations). I would create new subclass of TextSwitcher and some methods e.g. setColour() which can set the new colour and then trigger an animation. The animation code can then be moved outside of your main application.
make sure you keep a handle on the two TextViews that are put into the switcher
change the colour of the other TextView and call setText() to animate between them
If you are already using a ViewSwitcher then I don't think there is an easier way to implement this.
As others mention, using ObjectAnimator solves for this. However, in the existing posts - I wasn't seeing how to set duration. For me the color change would happen immediately.
The solution below shows:
setting the animation with some interval; thanks to post: https://plus.google.com/+CyrilMottier/posts/X4yoNHHszwq
a way to continuously cycle back and forth between the 2 colors
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();
}
I scrapped the variant of the 2 TextViews since it looked weird (edges weren't smooth and, since I have a lot of such elements on the screen it was really lagging the scrolling). What I did, was a crazy hack that does the animation with the use of a Thread and setTextColor (that also forces redraw of a textview).
Since I needed only 2 color changes (from red to white, and from green to white) I hardcoded the values and all of the transition colors between them. So here's how it looks:
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;
}
}
}
The issue I found with valueAnimator as well as ObjectAnimator is that the animator iterates through a number of random colors, and the transition doesn't look smooth. I wrote the following code which worked smoothly. Hope it helps someone else also.
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();
}

Categories

Resources