I'm trying to animate a long value using a ValueAnimator. The ValueAnimator doesn't have an .ofLong(long... values) builder. What is the best way to achieve this? Casting the longs to an int doesn't give me the result I'm looking for.
I encountered the same problem while building a scrolling time based view with scroll position as a long value of milliseconds. I ended up refactoring to use an int value of seconds, but if that is not appropriate for you here is my original solution. If you are using very large longs, the multiplying with floats and casting back to longs may cause inaccuracies, but give it a shot...
// There is a long somewhere that needs to be animated. Let's call it valueToAnimate
// This assumes it's a millisecond value for a time based scrolling view.
// Make a final copy of it for the animator
final long startValue = valueToAnimate;
// Also make a final reference to the target long for the animator
final long finishValue = valueToAnimate + 1000 * 60 * 60 * 24 * 14; // animate to 2 weeks from now
// Calculate distance needed to travel
final long distance = finishValue - startValue;
// Create a ValueAnimator of floats from 0 through to 1.
ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
long valueToAnimate = startValue + (long) (distance * (float) animation.getAnimatedValue());
}
});
animator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
// Make sure you end on the correct value
valueToAnimate = finishValue;
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
Related
I have a question of RotationAnimation.
First.
Is there a Listener to during animation?
start, start animation
repeat, repeat animation
stop, stop animation.
but there are no animation listener to check the on going.
second,
is any other get a current rotate angle of image?
I think, ImageView is rotate by rotationAnimation function.
so I made a timer thread and run 1second
'''
timer = new Timer();
timerTask = new TimerTask() {
public void run(){
Log.e("LOG", " [angle]: " + String.format("%3.1f", rotateImage.getRotation());
}
};
timer.schedule(timerTask, 0, 1000);
'''
but, I can't see the changed value during rotate.
how can I get the current angle during rotate?
thanks.
For Rotation Animation, Yes There is as shown below:
RotateAnimation rotateAnimation = new RotateAnimation();
rotateAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
You can also use Object Animators to animate Rotation:
ObjectAnimator rotateAnimation = ObjectAnimator.ofFloat(targetView, View.ROTATION, startAngle, endAngle);
rotateAnimation.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
To get the angle of your ImageView simply use imageView.getRotation(); this will give you an int value of the current angle of rotation.
You also don't need Timer because both ObjectAnimator and rotateAnimator provide time control for you:
rotateAnimation.setDuration(1000); // run animation for 1000 milliseconds or 1 second
rotateAnimation.setStartDelay(1000); // delay animation for 1000 milliseconds or 1 second
Finally, To get rotation Angle DURING the time animation is running there is a listener method called addUpdateListener :
rotateAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue(); // dynamic value of angle
}
});
I want to create timer progress bar for 1 minute. I've used following code but it is starting from 60 to 0 whereas using same procedure I've to start from 0 to 60.
public static void animateTimerProgress(int currentTimeDuration, final int maxTimeDuration, boolean withStartDelay, final DonutProgress timeOutProgressView, Runnable endAction) {
final int duration = currentTimeDuration < 0 ? 1 : currentTimeDuration;
timeOutProgressView.setMax(maxTimeDuration);
timeOutProgressView.setProgress(duration);
timeOutProgressView.animate()
.setDuration(duration * SECOND_IN_MILLIS)
.setInterpolator(new LinearInterpolator())
.setStartDelay(withStartDelay ? TIMEOUT_START_DELAY : 0)
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int progress = 1 + (int) ((1f - valueAnimator.getAnimatedFraction()) * (duration - 1f));
timeOutProgressView.setProgress(progress);
}
})
.withEndAction(endAction)
.start();
}
Any help would be appreciated.
you can use ValueAnimator like this
ValueAnimator animator = ValueAnimator.ofInt(0, 60);
animator.setDuration(duration * SECOND_IN_MILLIS);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
timeOutProgressView.setProgress((int) animation.getAnimatedValue());
}
});
animator.start();
On Kotlin, you can use 2 extension functions to help with that, incrementing 1 by 1 on progress. In this way, you can have a smoother animation:
/**
* ProgressBar Extensions
*/
fun ProgressBar.setBigMax(max: Int) {
this.max = max * 1000
}
fun ProgressBar.animateTo(progressTo: Int, startDelay: Long) {
val animation = ObjectAnimator.ofInt(
this,
"progress",
this.progress,
progressTo * 1000
)
animation.duration = 500
animation.interpolator = DecelerateInterpolator()
animation.startDelay = startDelay
animation.start()
}
How to use it:
progress.setBigMax(10)
progress.animateTo(10, 100)
Use following code to get your progress
int progress = 1 + (int) (valueAnimator.getAnimatedFraction() * (duration - 1f));
valueAnimator.getAnimatedFraction() gives the fraction value of your animation. You need to multiply by the max progress/duration to get current value of progress.
make a class
public class Anim {
public static void fadeOutProgressLayout(Activity act, final ViewGroup progressLayout) {
act.runOnUiThread(new Runnable() {
#Override
public void run() {
Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator());
fadeOut.setDuration(300);
fadeOut.setAnimationListener(new Animation.AnimationListener()
{
public void onAnimationEnd(Animation animation)
{
progressLayout.setVisibility(View.GONE);
}
public void onAnimationRepeat(Animation animation) {}
public void onAnimationStart(Animation animation) {}
});
progressLayout.startAnimation(fadeOut);
}
});
}
}
and write this line where ever you want the progress to go
Anim.fadeOutProgressLayout(GamblingVideosActivity.this, progressLayout);
In my app a large text in textview scroll up automatically with translate animation, and i designed two button for decrease and increasing speed, but when I change the duration it's work after last duration so it is not on-the-fly, but I want whenever I clicked, in that moment duration changed.In fact I want to do like how to change the duration of AnimationDrawable on the fly/runtime? ,but, with "Translation animation"
Here is what I did for randomly blinking light
final ImageView imageLight = (ImageView)findViewById(R.id.imageLight);
lastLightAlpha = (float) Math.random();
AlphaAnimation blinkLightAnimation = new AlphaAnimation(1.0f, lastLightAlpha);
blinkLightAnimation.setDuration((long) (Math.random() * 3000));
blinkLightAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
float newAlpha = (float) Math.random();
AlphaAnimation blinkLightAnimation = new AlphaAnimation(lastLightAlpha, newAlpha);
blinkLightAnimation.setAnimationListener(this);
blinkLightAnimation.setDuration((long) (Math.random() * 3000));
lastLightAlpha = newAlpha;
imageLight.startAnimation(blinkLightAnimation);
}
});
imageLight.startAnimation(blinkLightAnimation);
You can also reset your animation by
gearAnimation.cancel();
gearAnimation.reset();
I hope you can use parts of this code to solve your issue.
I'm implementing a slot machine in Android. The reels are ScrollViews with LinearLayouts as children, and the individual tiles as ImageViews vertically oriented inside the LinearLayout. I'm using an ObjectAnimator to scroll to the end of the ScrollView, using ValueAnimator.RESTART and ValueAnimator.INFINITE. The reel scrolling is nice and smooth, however when it comes time to repeat, it pauses for a second, which ruins the effect. Here's the code I'm using:
public void spinReel(SlotReel reel) {
final int reelSize = this.context.getPixelsInDPs(64);
final SlotMachineView me = this;
final SlotReel myReel = reel;
ImageView[] tiles = reel.getTiles();
int delta = tiles.length - reel.currentTileNumber();
ObjectAnimator animator = ObjectAnimator.ofInt(reel, "scrollY", tiles.length * reelSize );
animator.setInterpolator(new LinearInterpolator());
animator.setDuration(delta * 75);
animator.setStartDelay(0);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
myReel.scrollTo(0, reelSize * 3);
}
});
animator.start();
}
Note that the jerkiness occurs whether or not I put the scrollTo in the Repeat callback.
Example video here:
You should try:
setRepeatMode(ValueAnimator.INFINITE);
look here
Android ValueAnimator pauses during repeat
I am Trying to animate 3 images one after the other using value animator but i am not able to decide how to call the three handlers after regular intervals..Suppose there are 3 images and i m making three handlers for animating them.But i am able to bring the three images at a time but not one after the other at regular intervals.Please Help
This is my UpdateListener which i am calling from my handler
public void startAnimation_image(final ImageView aniView) {
animator = ValueAnimator.ofFloat(0, .8f);
animator.setDuration(Constants.ANIM_DURATION);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int Low = 10;
int High = width-150;
int R = (int) ((Math.random() * (High - Low)) + Low);
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = ((Float) (animation.getAnimatedValue())).floatValue();
aniView.setTranslationX(R);
Log.e("mscale",150*mScale +"");
Log.e("value is", value+"");
aniView.setTranslationY((mDisplaySize.bottom + (150*mScale))*value);
x_point = aniView.getTranslationX();
y_point = aniView.getTranslationY();
}
});
animator.addListener(new AnimatorListener() {
#Override
public void onAnimationStart(Animator arg0) {
}
#Override
public void onAnimationRepeat(Animator arg0) {
}
#Override
public void onAnimationEnd(Animator arg0) {
startAnimation();
}
#Override
public void onAnimationCancel(Animator arg0) {
}
});
animator.start();
}
This is one of my handler
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//int viewId = new Random().nextInt(STARS.length);
id = getApplicationContext().getResources().getIdentifier(STARS[0], "drawable",
getApplicationContext().getPackageName());
inflate = LayoutInflater.from(StarsActivity2.this);
img[0].setVisibility(ImageView.VISIBLE);
img[0].setImageResource(id);
mAllImageViews.add(img[0]);
LayoutParams animationLayout = (LayoutParams) img[0].getLayoutParams();
img[0].setLayoutParams(animationLayout);
Log.e("mHandler",img[0]+ "");
startAnimation_image(img[0]);
}
};
There are similaarly three handlers and three update listeners.. Please help...
You can delay an animation by offset ms by calling
animation.setStartOffset(offset);
So for three images with duration ANIM_DURATION, you can use the following values to start them sequentially (probably by passing them as a parameter to startAnimation_image())
// note: this is for illustrative purposes. You should put this in a loop
int firstOffset = 0 * ANIM_DURATION; // starts immediately
int secondOffset = 1 * ANIM_DURATION; // starts after the first animation is finished
int thirdOffset = 2 * ANIM_DURATION; // starts after the second animation is finished
// ... and so on.