In my Android project, I have a Button which is supposed to "animate out" after being clicked (and stay hidden). The effect is implemented as an AnimationSet defined in anim resources, which I'm loading using AnimationUtils. To freeze the animation on its last frame, I'm using setFillAfter(true).
private Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_temp);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (v != button) return;
this.runOnUiThread(new Runnable() {
#Override
public void run() {
Animation animation = AnimationUtils.loadAnimation(button.getContext(), R.anim.out_to_back);
animation.setFillAfter(true);
button.startAnimation(animation);
}
});
}
The animation resource itself is defined as follows:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
android:fillAfter="true"
android:duration="400">
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.0" />
<scale
android:fromXScale="1"
android:toXScale="0"
android:fromYScale="1"
android:toYScale="0"
android:pivotX="50%"
android:pivotY="50%" />
</set>
After being clicked, the button animates as expected. The problem is, however, that the animation resets when I click anywhere else. A simple demo:
Is this a bug, or am I missing something really obvious? Thanks for any ideas!
Additional information
it doesn't matter whether I set fillAfter in code, in the XML resource, or both
when setting it in XML, it doesn't matter whether I apply it on the <set> element, or on both of the individual "components" <alpha> and <scale>
the preview was captured on an emulator running API 16
this does not happen on API 22
PS: I'm aware I'm better off using Animator, not the Animation APIs (unless I need to target pre-Honeycomb, which I don't)
I'm probably gonna switch to Animator anyway and see if this behavior persists. But I'm curious what's going on here anyway!
One thing you can try right away is to set the android:fillEnabled="true" attribute in your animation xml along with fillAfter. I'm not sure if that will help, but I know that's worked for some scenarios.
If that doesn't work, your other option is to set an AnimationListener for your animation, and then set your button's visibility to GONE once the animation has completed. This will make it so once the fade out happens, the button will be removed from the View until you choose to bring it back again. It would look something like this:
Animation animation = AnimationUtils.loadAnimation(button.getContext(), R.anim.out_to_back);
animation.setFillAfter(true);
animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
button.setVisibility(View.GONE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
button.startAnimation(animation);
It may complain that your button variable is not final. You should be able to fix that by simply assigning the View that comes in through your onClick method to a local final variable, like final View buttonView = v;
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'm working on animating a View from within a GridLayout. When I access the view from the View.OnClickListener onClick(View view) method the animation runs smoothly.
However, when I get Views via gridLayout.getChildAt(i) the animation skips straight to the ending position.
view.animate()
.translationX(viewAnimation.xTransform)
.translationY(viewAnimation.yTransform)
.setDuration(200)
.setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
//Code
}
#Override
public void onAnimationEnd(Animator animator) {
if (reloadGrid)
//Code
else
animate(viewAnimations);
}
//Other methods here
});
I'm really unsure as to why when the View is passed as a parameter it animates fine, however otherwise it skips.
Any advice would be great!
Edit
I have also checked and the difference between the 2 'View' objects is one has mDrawable set and one doesn't. I believe this could be the cause?
I'm not really sure why this solves the problem, however accessing each View within the GridLayout via findViewById(i) seems to work, and then allow the animation to run smoothly.
This took way too long to figure out.
I have an animation(xml) file that sets an image view to appear like the credits of a movie:
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator" >
<translate
android:duration="10000"
android:fromYDelta="100%p"
android:toYDelta="0%p" />
</set>
As you can see, the image stops "moving" when it gets full screen. This is ok.
My question is: how can I set a textView (hidden) visible when this IV reaches de end of the animation, so the text can be over the image?
The java code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_final);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
mozart=(ImageView) findViewById(R.id.mozart);
Picasso.with(this).load(R.drawable.amadeus).fit().centerCrop().into(mozart);
read=(TextView) findViewById(R.id.read);
restart=(Button) findViewById(R.id.restart);
restart.setOnClickListener(this);
Animation moz= AnimationUtils.loadAnimation(this, R.anim.animation);
mozart.startAnimation(moz);
read.setVisibility(View.INVISIBLE);
read.setText("Text to appear with other alphaAnimation");
}
#Override
public void onClick(View view) {
if (view == restart) {
allaTurca.stop();
Intent a = new Intent(this, MainActivity.class);
startActivity(a);
this.finish();
}
}
}
Is it possible? I've tried several aproaches, but I cant't figure out how to tell the program when the image is ready to "receive" the text. Thaks for the help
FOR ANIMATION START REPEAT AND END
You have to add an animation listener to the animation like this
moz.setAnimationListener(new Animation.AnimationListener(){
#Override
public void onAnimationStart(Animation arg0) {
//Do Something on start
}
#Override
public void onAnimationRepeat(Animation arg0) {
}
#Override
public void onAnimationEnd(Animation arg0) {
}
});
When the animation starts it will first pass through the onStart( this is where u can initialize variables for animation) ...
then if you have repetition in your animation onAnimationRepeat will be called.
When the Animation is finished the onAnimationEnd will be called. ( This is the part you are interested in)
EDIT
As pointed out in the comments ... the better way of doing this is using AnimatorListenerAdapter .... thank you marmor
AnimatorListenerAdapter onEnd = new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator _a) {
DropZone.this.setTranslationY(getHeight() + 2);
DropZone.this.setAlpha(0f);
}
};
You can find examples here http://www.programcreek.com/java-api-examples/index.php?api=android.animation.AnimatorListenerAdapter
So I am developing Android application in which I have a Home screen and another screen with the content of the app. On home screen I have a button which navigates the user to the content's screen (actually it is image view but used as a button).
When clicked this button should start animation of itself being clicked and then start the activity of the content screen.
But it actually works pretty bad and slow, when I click the button the animation starts but it slows down (lags). I tried changing the event from click to tap and lots of other possible solutions but none worked.
I tried commenting "startActivity" method and this fixed it, the animation was running smoothly. Obviously I need the startActivity method, so what is the best approach here, how can I fix this. Can putting startActivity in different thread work, I'm not sure how to do this if so as well
This is my code:
((Button)findViewById(R.id.btnPlay)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
//shake.reset();
findViewById(R.id.btnPlay).startAnimation(shake);
shake.setAnimationListener(new Animation.AnimationListener() {
Intent i;
#Override
public void onAnimationStart(Animation animation) {
i = new Intent(v.getContext(), GameActivity.class);
startActivity(i);
}
#Override
public void onAnimationEnd(Animation animation) {
((Button) findViewById(R.id.btnPlay)).setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
});
shake is an animation loaded from custom xml file. I have the same animation in the content screen and it runs smoothly, of course there is no startActivity there. Here is the code:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:duration="70"
android:fromDegrees="-5"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="5"
android:repeatMode="reverse"
android:interpolator="#android:anim/linear_interpolator"
android:toDegrees="5" />
<translate
android:fromXDelta="-10"
android:toXDelta="10"
android:repeatCount="5"
android:repeatMode="reverse"
android:interpolator="#android:anim/linear_interpolator"
android:duration="70" />
Move these lines of code in onAnimationEnd()
i = new Intent(v.getContext(), GameActivity.class);
startActivity(i);
UPDATE
I've just tried this code and it works well for me:
Animation animation = AnimationUtils.loadAnimation(MyApplication.getAppContext(), R.anim.shake);
public void onClick(View v) {
if (v.getId() == R.id.btnPlay) {
animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
Intent intent = new Intent(getActivity(), ArticleActivity.class);
startActivity(intent);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
v.startAnimation(animation);
}
}
If the activity starts when the animation of the button starts, there could be too many things (like: button animation, execution of activity lifecycle methods including the lifecycle methods of the fragments, the animation used for transition between activities) which are executed on the main thread => the button animation could get stuck (the animation won't be smooth).
I have a class that extends DialogFragment, and I would like to add animation when the user presses the back button from that fragment
public class myClass extends DialogFragment{
private void myAnimation(){
// code here for animation...
}
}
How can I call myAnimation() when the user presses the back button from this fragment?
There are many animation you can choose for here take a look below:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator">
<translate
android:fromXDelta="0"
android:toXDelta="100%p"
android:duration="500"
android:repeatCount="1"
android:repeatMode="reverse"/> //File name is anim_translate.xml
</set>
final Animation animTranslate = AnimationUtils.loadAnimation(this, R.anim.anim_translate)
Button btnTranslate = (Button)findViewById(R.id.translate);
btnTranslate.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View view) {
view.startAnimation(animTranslate);
}});
Take a look at this site AndroidAnimation
You can add animations into FragmentTransaction by method setCustomAnimations (int enter, int exit, int popEnter, int popExit) which is used to show DialogFragment(DialogFragment.show(transaction, tag)
).And you also need to invoke the method addToBackStack(tag) to make popExit animation avaliable.
So when you clicked the back button,it will automatically play the animation you have assigned(popExit animation).
Check the setCustomAnimations method here