I have ImageView that I want to animate it whenever user clicks on it.
So I ended up with this simple solution:
public void onClick(View v) {
imageView.animate()
.rotationX(360).rotationY(360)
.setDuration(1000)
.setInterpolator(new LinearInterpolator());
}
It works just perfect, but only FIRST TIME (first click plays animation, after that animation does not work at all).
How can I fix that?
You need to reset the rotation before or after each animation. For example:
imageView.animate()
.rotationX(360).rotationY(360)
.setDuration(1000)
.setInterpolator(new LinearInterpolator())
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animator) {
imageView.setRotationX(0);
imageView.setRotationY(0);
}
});
Related
I am developing a mobile game, in the game, the user presses buttons before they shrink, in order to make the game 'fun,' the buttons shrink at a faster and faster rate, so when the user presses one button, another button pops up that shrinks faster. So far I have this code which handles the user input and shrinking of the button, however, once pressed there is no animation, it instantly snaps to the 'shrunk' size, I'm not sure how to go about fixing this issue.
button.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View arg0) {
ViewGroup.LayoutParams params = button.getLayoutParams();
Integer value = 120;
while(value >= 2) {
value = value - 1;
SystemClock.sleep(50);
params.width = value;
params.height = value;
button.setLayoutParams(params);
};
}
});
I added the SystemClock.sleep(50) line as I thought that is why it was snapping (i.e. it was so quick that I just didn't see the animation) but that is not the case as the app just hangs until the button's size is updated.
P.s. I am quite new when it comes to developing mobile apps.
Edit
Forget what I wrote in my original post. Please try the code below and let me know whether this helps you out.
final ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f, 0.0f); //start and end value
valueAnimator.setDuration(2000); //you can replace 2000 with a variable you can change dynamically
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
button.setScaleX(animatedValue);
button.setScaleY(animatedValue);
}
});
valueAnimator.start();
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
valueAnimator.pause();
}
});
Original answer
I would follow the suggestion of 0X0nosugar.
In your Android file tree, under your res directory, add an Android Resource Directory (right-click on res folder > new) and call it "anim". Android Studio probably automatically treat as a folder which holds animation if you use that name.
Right-click again on the anim-folder > new > Animation resource file.
Name it what you want. In my example I have named it button_animator.
Your file tree will look like this:
Your button_animator.xml could look like this:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:fromXScale="1.0"
android:toXScale="0.1"
android:fromYScale="1.0"
android:toYScale="0.1"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="500" />
</set>
You can tailor the end scale of the button using these lines:
android:toXScale="0.1"
and
android:toYScale="0.1"
Inside your code you can dynamically tailor your animation:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Animation shrinkButton = AnimationUtils.loadAnimation(MainActivity.this, R.anim.button_animator); //reference the animator
shrinkButton.setDuration(5000); //dynamically set the duration of your animation
button.startAnimation(shrinkButton); //start the animation. Since it is inside an onclicklistener, the animation start on a button click event
shrinkButton.setAnimationListener(new Animation.AnimationListener() { //you could use an AnimationListener to do something on certain event, like at the end of the animation
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) { //you probably want to something onAnimationEnd, otherwise the button will snap back into its original size.
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
});
In the onAnimationEnd you have to decide what you want to do at the end of the animation. Just a couple of ideas:
#Override
public void onAnimationEnd(Animation animation) { //you probably want to something onAnimationEnd, otherwise the button will snap back into its original size.
button.setScaleX(0.1f); //same size as in toScale size in the animator xml
button.setScaleY(0.1f);
}
Or, if you want the button to become invisible:
#Override
public void onAnimationEnd(Animation animation) {
button.setVisibility(View.INVISIBLE);
}
I have a ViewPager in my app, and I'd like it to shake when it is loaded for the first time. This is to show the user that there are more pages available. How can I achieve that programmatically?
However, I don't want the pager to automatically scroll to the next page.
ViewPager has a method for swiping programmatically: fakeDragBy
https://developer.android.com/reference/android/support/v4/view/ViewPager.html#fakeDragBy(float)
Here's how you can achieve this:
Call viewPager.beginFakeDrag()
Start an animator. In the AnimatorUpdateListener override onAnimationUpdate so it calls viewPager.fakeDragBy()
In the AnimatorListener override onAnimationEnd so it calls viewPager.endFakeDrag() After this call, the ViewPager should settle back to the initial page.
vpaliyX's answer using translation won't show the next page. You need to use fakeDragBy so that the user can briefly see the edge of the next page.
As requested, here is a code snippet:
private float drag;
...
#Override
protected void onResume() {
super.onResume();
mViewPager.postDelayed(new Runnable() {
#Override
public void run() {
mViewPager.beginFakeDrag();
drag = 0;
float density = getResources().getDisplayMetrics().density;
// 120 is the number of dps you want the page to move in total
ValueAnimator animator = ValueAnimator.ofFloat(0, 120 * density);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float progress = (float) valueAnimator.getAnimatedValue();
mViewPager.fakeDragBy(drag - progress);
drag = progress;
}
});
animator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) { }
#Override
public void onAnimationEnd(Animator animator) {
mViewPager.endFakeDrag();
}
#Override
public void onAnimationCancel(Animator animator) { }
#Override
public void onAnimationRepeat(Animator animator) { }
});
animator.setDuration(400);
animator.start();
}
}, 300);
}
I put in a 300 ms start delay. I don't really know if that's necessary or not.
Note the expression drag - progress which gives a negative number. To get a leftward swipe, you have to use a negative value.
Also note that I didn't include any code to determine if this was the first time the app was opened.
You can play with the start delay, the animation duration, and the number of dps to swipe until you get the effect you are looking for.
If you want to shake it, you can use animation for it.
I had done the same stuff for FloatingActionButton, and it worked perfectly.
For ViewPager check out this code:
ObjectAnimator shakeAnimation=ObjectAnimator.ofFloat(yourViewPager,View.TRANSLATION_X,-25f,25f);
shakeAnimation.setDuration(100);
shakeAnimation.setRepeatCount(2);
shakeAnimation.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
yourViewPager.setTranslationY(0f);
}
});
shakeAnimation.start();
You can adjust the translation as convenient for, in my case it's just [-25,25].Also you can set a duration of animation, and the repeat count.
You can use this code for your ViewPager when the data has been loaded for the first time, however, you need to determine when the data has been loaded for the first time. But I don't think you will have problems with that.
Good luck!
these are just the methods i can override during animationListener.
http://developer.android.com/reference/android/view/animation/Animation.AnimationListener.html
Animation animation
animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.device_box);
animation.setAnimationListener(new AnimationListener(){
#Overridepublic void onAnimationEnd(Animation arg0) {}
#Override public void onAnimationRepeat(Animation animation) {}
#Override public void onAnimationStart(Animation animation) {}});
I think adding a thread in onAnimationStart and stop it on onAnimationEnd and getting the coordinates with a loop inside the thread, this may work.
But i think that i could get some problems with buttons because, when animating them in this way, only the background moves, not button area itself
In this case, i have to investigate more with buttons
What do you think about this, is there another way to achieve what i want?
Is this the better way to do it ?
I researched, and what I got is this, not X and Y but can handle the data as get what has been animated as time.
ObjectAnimator anim = ObjectAnimator.ofFloat(box_image, "translationX", 0 , cant);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator arg0) {
double f = Math.round(arg0.getAnimatedFraction()*1000.0)/1000.0;
Log.d("datos", ""+f);
}
});
anim.setDuration(1000);
anim.start();
i use this code to when i click on a imagebox, run an animation on another object and dissaper itself via visibility.GONE. but it doesnt work!! here is my code:
againbtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//answer button on animation
Animation anim2 = AnimationUtils.loadAnimation(MainActivity.this, R.anim.askbtnonanim);
anim2.setFillAfter(true);
askbtn.startAnimation(anim2);
//gone myselft (againbtn)
againbtn.setVisibility(View.GONE);
}
});
if a delete 3 animation line from this code, everything is OK and works, but now it doesn't. but why? it's related to anim2.setFillAfter(true); ??? i put this because my animation run one time and dont reset! please help me
Try this
You have to clear the view animation then you can setVisibility
animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
view.clearAnimation();
view.setVisibility(View.GONE);
}
#Override
public void onAnimationRepeat(Animation animation) {}
});
You should implement Animation Listener and in onAnimationEnd() you should perform your task... hope below code will help you...
anim2.setAnimationListener(new Animation.AnimationListener(){
#Override
public void onAnimationStart(Animation arg0) {
}
#Override
public void onAnimationRepeat(Animation arg0) {
}
#Override
public void onAnimationEnd(Animation arg0) {
againbtn.setVisibility(View.GONE); //set your button visibility here
}
});
I think put visibility button before animation coding the this might work
againbtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//gone myselft (againbtn)
againbtn.setVisibility(View.GONE);
//answer button on animation
Animation anim2 = AnimationUtils.loadAnimation(MainActivity.this, R.anim.askbtnonanim);
anim2.setFillAfter(true);
askbtn.startAnimation(anim2);
}
});
Calling clearAnimation() on the view that is doing the animation before calling View.INVISIBLE, or GONE does the trick.
use AnimationListener for setting Button Visibility GONE when Animation end.
.....
anim2.setAnimationListener(animButnListener);
askbtn.startAnimation(anim2);
AnimationListener animButnListener = new AnimationListener(){
#Override
public void onAnimationEnd(Animation animation) {
// make Button Visibility GONE here
againbtn.setVisibility(View.GONE);
}
//.......other AnimationListener methods
};
I want to make 2 animation on activity for 2 images, and I want to do it with 2 conditions:
1. I want to start the animation after the activity finished to load to page, so instead of putting animation code under onCreate i put it under onResume is that OK? There is a better way to do it?
2. I want the second animation will start only after the first animation is finished...
Thanks
You'll want to use an Animation.AnimationListner You can set one on your first animation that will get a callback when the animation is complete. Inside that callback you can add the code that will start the second animation.
Depending on the API level you are coding for you can use AnimationSet or AnimatorSet. Also if you are extending View or one of its subclasses you can override View.onAnimationStart() and View.onAnimationFinish(). Or use the listener Tim mentions.
public class SplashActivity extends Activity{
Animation FadeInanimation, FadeOutanimation;
ImageView img;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
img= (ImageView) findViewById(R.id.img);
//Your Code Block....
FadeInanimation = AnimationUtils.loadAnimation(this,R.anim.image_fadein);
//FadeInanimation.setRepeatCount(Animation.INFINITE);
//FadeInanimation.setRepeatMode(Animation.RESTART);
FadeInanimation.setAnimationListener(FadeInAnimationListener);
FadeOutanimation = AnimationUtils.loadAnimation(this,R.anim.image_fadeout);
//FadeOutanimation.setRepeatCount(Animation.INFINITE);
//FadeOutanimation.setRepeatMode(Animation.RESTART);
FadeOutanimation.setAnimationListener(fadeOutAnimationListener);
img.startAnimation(FadeInanimation);
}
AnimationListener FadeInAnimationListener = new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
plane.startAnimation(FadeOutanimation);
}
};
}