What I'm trying to do is load one animation on a view with a linear interpolator for example. Then, when a certain event happens in my application, change the interpolator to something like a deceleration interpolator. So the effect would be a constant animation until an event happened, then the animation would slow down to a stop. Is this possible to achieve? Im wondering how I would achieve this and would love some direction.
Thanks!
Yes. You would create a custom Interpolator for the animation. It contains the other interpolators that you want. When the event happens, just trigger it in the interpolator and have the interpolator swap one interpolator for the other.
public class CompositeInterpolator implements TimeInterpolator {
LinearInterpolator mLinear;
DecelerateInterpolator mDecelerate;
boolean mUseLinear = false;
public CompositeInterpolator() {
mLinear = new LinearInterpolator();
mDecelerate = new DecelerateInterpolator();
}
public void useLinear(boolean use) {
mUseLinear = use;
}
#Override
public float getInterpolation(float input) {
if (mUseLinear) {
return mLinear.getInterpolation(input);
} else {
return mDecelerate.getInterpolation(input);
}
}
}
Then just call useLinear(false) when you want to swap.
Related
I have a few buttons on a grid. I need that this buttons are animations. The animation is very simple, I only want that this buttons change his color and return o his original color, like a "simon game".
So, my problem is the next:
I have been trying make this with AnimatorSet. I make my own class for the buttons :
class Button{
ObjectAnimator anim;
public Button button;
public int colorA;
public int colorB;
public Button(){};
};
And I have:
private Boton[] buttons;
buttons = new Boton[numButtons];
for(int i=0; i<numButtons; i++)
buttons[i] = new Boton();
After:
for(int i=0; i<numButtons; i++){
buttons[i].animacion=ObjectAnimator.ofFloat(buttons[i], "alpha", 1f, 1f);
buttons[i].animacion.setStartDelay(1000);
buttons[i].animacion.setDuration(2000);
buttons[i].animacion.addListener(new miAnimador(i));
}
Also, I defined my own Listener:
class miAnimador implements Animator.AnimatorListener{
int numBoton;
public miAnimador(int num){
numBoton=num;
}
public void onAnimationCancel(Animator paramAnonymousAnimator) {
}
#Override
public void onAnimationEnd(Animator animator) {
buttons[numBoton].button.setBackgroundColor(buttons[numBoton].colorA);
}
#Override
public void onAnimationRepeat(Animator animator) {
}
#Override
public void onAnimationStart(Animator animator) {
buttons[numBoton].button.setBackgroundColor(buttons[numBoton].colorB);
}
};
This is very powerful for me because I can have a vector of buttons and launching his animation when I want.
After I can make this: build a animatorSet with the sequence of animations that I want.
AnimatorSet s = new AnimatorSet();
final List<Animator>listaAnimaciones = new ArrayList<Animator>();
final List<Animator>AnimationsSequence = new ArrayList<Animator>();
AnimationsSequence.add(buttons[0].anim);
AnimationsSequence.add(buttons[1].anim);
//Add list
s.playSequentially(AnimationSequence);
s.setStartDelay(5000);
//Start animation
s.start();
Well, this work well, and I like the form of the AnimatorSet work, but the problem occur when I try animate the same buttons twice.
The exception is: "Circular dependencies cannot exist in AnimatorSet" and i don't understand why this happening.
Be that as it may, I need make this, and I was thinking that this is the best solution, but:
If this don't work, how can get this?
I accept any idea.
If you thinking that this is bad solution, please I would like to know your opinion.
I'm trying to implement a Blink Animation.
This code makes a view to blink fade in and fade out:
AlphaAnimation blink = new AlphaAnimation(0.0f, 1.0f);
blink.setDuration(500);
blink.setStartOffset(0);
//changing it makes more than one animation appear in different time stamps.
blink.setRepeatMode(Animation.REVERSE);
blink.setRepeatCount(Animation.INFINITE);
I have two issues:
setStartOffset(n); --> Changing n makes more than one animation appear in different time stamps. Not synced. I want it to be synced, all animations should appear and dissappear at same time.
I do not want fade in or fade out, simply visible & gone with few millisecond delay.
Is there any other Class of Animation that i had to use, or i had to make a custom animation.
Pls. help.
For animation without the fading you can create your own custom Interpolator:
import android.view.animation.Interpolator;
public class StepInterpolator implements Interpolator {
float mDutyCycle;
public StepInterpolator(float dutyCycle) {
mDutyCycle = dutyCycle;
}
#Override
public float getInterpolation(float input) {
return input < mDutyCycle ? 0 : 1;
}
}
Then set the interpolator in the Animation object:
blink.setInterpolator(new StepInterpolator(0.5f));
So, my answer ... it's a class that toggles visibility of a view in a certain interval. Of course it can be solved differently, maybe you get some inspiration...
public static class ViewBlinker {
private Handler handler = new Handler();
private Runnable blinker;
public ViewBlinker(final View v, final int interval) {
this.blinker = new Runnable() {
#Override
public void run() {
v.setVisibility(v.getVisibility()==View.VISIBLE?View.INVISIBLE:View.VISIBLE);
handler.postDelayed(blinker, interval);
}
};
}
public void startBlinking() {
handler.post(blinker);
}
public void stopBlinking() {
handler.removeCallbacks(blinker);
}
}
and you use it like this :
ViewBlinker blinker = new ViewBlinker(YOUR_BLINK_VIEW, YOUR_BLINK_INTERVAL);
blinker.startBlinking();
and when your view is finished blinking, call
blinker.stopBlinking();
Actually, based on cold ash's answer in 2014, all of his/her code can be simplified as below (thanks to lambda):
blink.setInterpolator(input -> input < 0.5f ? 0 : 1);
Yes, just a single line. Very simple.
I have successfully written a new interpolator for a view animation by implementing the Interpolator interface like this.
public class MyInterpolator implements Interpolator {
public MyInterpolator() {}
public float getInterpolation(float t) {
return somefunction(t);
}
}
I know that I can use this interpolator programmatically by creating an instance and passing it to the setInterpolator method of the Animation class.
But is there a way of using MyInterpolator in the XML resources for my animations?
Searching for the same thing, I encounter that android give support to this.Android Custom Interpolators
I want to build an animation of TextViews, which repeats itself just after completion.
For each View I want to animate, I use the following piece of code
final float oldX = v.getX();
final float newX = v.getX() - (float)totalWidth;
final AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
v.setX(oldX);
animFinished = true;
//This line won't compile
//v.animate().setDuration(animDuration).setInterpolator(newsInterpolator)
// .setListener(listener).x(newX);
}
};
v.animate().setDuration(animDuration).setInterpolator(newsInterpolator)
.setListener(listener).x(newX);
I tried to place the last piece of code into the onAnimationEnd, but Java will not compile since it considers the object listener as not initialized. Moreover, I don't think that this "recursive" animation invocation is a good solution, it was the first thing which came to my mind. I am suspicious that there is a simple and sound way to implement looping property animation, but I failed to locate it, so I turned here for help.
Thanks in advance
Well, I am going to answer myself again.
TranslateAnimation class has methods about repeating the animation, so I used it instead of ViewPropertyAnimator.
The following code seems to work:
long duration = 1000* ((long)totalWidth / newsScrollSpeed);
System.out.println("totalWidth="+totalWidth);
TranslateAnimation anim = new TranslateAnimation(0,-totalWidth,0,0);
anim.setInterpolator(linearInterpolator);
anim.setDuration(duration);
anim.setRepeatCount(TranslateAnimation.INFINITE);
anim.setRepeatMode(TranslateAnimation.RESTART);
for(i=0;i<this.getChildCount();i++)
{
View v = this.getChildAt(i);
if(v.getId() == R.id.yuruyen_yazi)
{
continue;
}
v.startAnimation(anim);
}
Not elegant way, but it works:
Runnable runnable = new Runnable() {
#Override
public void run() {
// update newX
v.animate().setDuration(animDuration).setInterpolator(newsInterpolator).x(newX).withEndAction(this).start();
}
};
v.animate().setDuration(animDuration).setInterpolator(newsInterpolator).x(newX).withEndAction(runnable).start();
I would like to apply successive animations (say ScaleAnimation) to an ImageView showing a resource image. The animation is triggered by a button. For example, I would like to incrementally enlarge an image upon each button click.
I've set fillAfter="true" on the animation. However, all the animations start from the original state of the ImageView. It seems as if the ImageView resets its state and the animation is always the same, instead of starting from the final state of the previous animation.
What am I doing wrong?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button)findViewById(R.id.Button01);
button.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
animate();
}});
}
private void animate() {
ImageView imageView = (ImageView) findViewById(R.id.ImageView01);
ScaleAnimation scale = new ScaleAnimation((float)1.0, (float)1.5, (float)1.0, (float)1.5);
scale.setFillAfter(true);
scale.setDuration(500);
imageView.startAnimation(scale);
}
It seems as if the ImageView resets
its state and the animation is always
the same, instead of starting from the
final state of the previous animation.
Precisely! I'm sure there's a use for fillAfter="true", but I haven't figured out the point for it yet.
What you need to do is set up an AnimationListener on each Animation of relevance, and do something in the listener's onAnimationEnd() to actually persist the end state of your animation. I haven't played with ScaleAnimation so I'm not quite sure what the way to "persist the end state" would be. If this were an AlphaAnimation, going from 1.0 to 0.0, you would make the widget INVISIBLE or GONE in onAnimationEnd(), for example.
I've had the same problem and created the following code to easily use different animations. It only supports translation and alpha levels for now as I haven't used scaling, but could easily be extended to support more features.
I reset the scroll and the visibility before starting the animation, but that's just because I needed on/off animations.
And the "doEnd" boolean is there to avoid a stack overflow on the recursion (scrollTo calls onAnimationEnd for some obscure reason...)
private void setViewPos(View view, Animation anim, long time){
// Get the transformation
Transformation trans = new Transformation();
anim.getTransformation(time, trans);
// Get the matrix values
float[] values = new float[9];
Matrix m = trans.getMatrix();
m.getValues(values);
// Get the position and apply the scroll
final float x = values[Matrix.MTRANS_X];
final float y = values[Matrix.MTRANS_Y];
view.scrollTo(-(int)x, -(int)y);
// Show/hide depending on final alpha level
if (trans.getAlpha() > 0.5){
view.setVisibility(VISIBLE);
} else {
view.setVisibility(INVISIBLE);
}
}
private void applyAnimation(final View view, final Animation anim){
view.scrollTo(0, 0);
view.setVisibility(VISIBLE);
anim.setAnimationListener(new AnimationListener(){
private boolean doEnd = true;
#Override
public void onAnimationEnd(Animation animation) {
if (doEnd){
doEnd = false;
setViewPos(view, animation, anim.getStartTime() + anim.getDuration());
}
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
}
});
view.startAnimation(anim);
}