I have an ImageView that gets animated when it is added to a layout.
When it is removed, I want to reverse the same animation.
Is there a way to reverse an animation in android without recoding it and reversing the parameters?
No, sadly you cannot do it with the Animation object.
But you can simulate it using an interpolator that will inverse the animation:
package com.example.android;
import android.view.animation.Interpolator;
public class ReverseInterpolator implements Interpolator {
#Override
public float getInterpolation(float paramFloat) {
return Math.abs(paramFloat -1f);
}
}
Then on your animation you can set your new interpolator:
myAnimation.setInterpolator(new ReverseInterpolator());
If you are using Object or ValueAnimator to animate the view, you can simply do
ValueAnimator myAnimator = new ValueAnimator();
myAnimator.reverse()
Documentation can be found here.
Based on pcans idea, you can reverse any interpolator, not just linear.
class ReverseInterpolator implements Interpolator{
private final Interpolator delegate;
public ReverseInterpolator(Interpolator delegate){
this.delegate = delegate;
}
public ReverseInterpolator(){
this(new LinearInterpolator());
}
#Override
public float getInterpolation(float input) {
return 1 - delegate.getInterpolation(input);
}
}
Usage
ReverseInterpolator reverseInterpolator = new ReverseInterpolator(new AccelerateInterpolator())
myAnimation.setInterpolator(reverseInterpolator);
I have a similar approach to pcans buts slightly different. It takes an Interpolator and will effectively pass out values that would be the same as using the passed in Interpolator normally and then in REVERSE mode. Saves you having to think about the buggy implementations of Animation.REVERSE across Android. See the code here
public class ReverseInterpolator implements Interpolator {
private final Interpolator mInterpolator;
public ReverseInterpolator(Interpolator interpolator){
mInterpolator = interpolator;
}
#Override
public float getInterpolation(float input) {
return mInterpolator.getInterpolation(reverseInput(input));
}
/**
* Map value so 0-0.5 = 0-1 and 0.5-1 = 1-0
*/
private float reverseInput(float input){
if(input <= 0.5)
return input*2;
else
return Math.abs(input-1)*2;
}
}
Simplest solution i came up with
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="#android:anim/linear_interpolator">
<alpha
android:duration="2000"
android:fromAlpha="0.1"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:toAlpha="1.0">
</alpha>
</set>
You can make the code remember the original position and the end position. And let your code dynamically get those values when triggering animation.
If you are using animation from xml then an easy way is to made an exact same reverse animation to original animation. Add Animation.AnimationListener to original animation and in onAnimationEnd method start the reverse animation.
this worked for me
ObjectAnimator anim = ObjectAnimator.ofFloat(imageViewUpb, "rotation", rotationAngle, rotationAngle + 180);
if (linearLayoutb.getVisibility()==GONE){
linearLayoutb.setVisibility(VISIBLE);
anim.setDuration(500);
anim.start();
rotationAngle += 180;
rotationAngle = rotationAngle%360;
imageViewUpb.animate().rotation(rotationAngle).setDuration(500).start();
}else{
linearLayoutb.setVisibility(GONE);
anim.setDuration(500);
anim.start();
rotationAngle += 180;
rotationAngle = rotationAngle%180;
imageViewUpDownb.animate().rotation(rotationAngle).setDuration(500).start();
}
linearlayoutb is the view that expands when the imageviewUpb faces up
make int rotationAngle = 0; global parameter
You need to use RepeatCount and RepeatMode
kotlin
var anim = TranslateAnimation(0, 100, 0, 100)
anim.repeatCount = Animation.INFINITE // you cant 1,2,...
anim.repeatMode = Animation.REVERSE // you can set REVERSE or RESTART
anim.start()
Since other answers have already been answered in Java, I will answer in Kotlin
// code inside onViewCreated()
...
var anim: TranslateAnimation = TranslateAnimation(0F,60F,0F, 0F)
anim.duration = 3000
anim.fillAfter = true
anim.repeatCount = -1
anim.repeatMode = Animation.REVERSE // back and forth
binding.asteroid.startAnimation(anim)
...
This is the simplest approach in Kotlin.
Related
I was working on animated effect on android, I would like to know if there's any other way to gradually increase/decrease the animation speed?
Is it possible to specify like first 3 second rate of change was slow, and the rest goes fast?
Use a Interpolator. For your case I would recommend the AccelerateDecelerateInterpolator
Animation anim = AnimationUtils.loadAnimation(this, R.anim.your_animation);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
image.startAnimation(anim);
As for the interpolator, you can build your own!
public class MyInterpolator extends Interpolator {
public MyInterpolator(int valueCount) {
super(valueCount);
}
public float getInterpolation (float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
}
Using Wolfram Alpha you can play with the parameters.
Using this code I only have a fade in, I'm looking for how to add a fade out as well. I've added another xml called "fadeout" but I can't integrate it in my code.
ImageView imageView = (ImageView)findViewById(R.id.imageView);
Animation fadeInAnimation = AnimationUtils.loadAnimation(this, R.anim.fadein);
imageView.startAnimation(fadeInAnimation);
button1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
imageView.startAnimation(fadeInAnimation);
}
}
fadein.xml
<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:interpolator="#android:anim/accelerate_interpolator"
android:duration="Your Duration(in milisecond)"
android:repeatCount="infinite"/>
</set>
Here is my solution. It uses AnimatorSet. AnimationSet library was too buggy to get working. This provides seamless and infinite transitions between fade in and out.
public static void setAlphaAnimation(View v) {
ObjectAnimator fadeOut = ObjectAnimator.ofFloat(v, "alpha", 1f, .3f);
fadeOut.setDuration(2000);
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(v, "alpha", .3f, 1f);
fadeIn.setDuration(2000);
final AnimatorSet mAnimationSet = new AnimatorSet();
mAnimationSet.play(fadeIn).after(fadeOut);
mAnimationSet.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mAnimationSet.start();
}
});
mAnimationSet.start();
}
This is Good Example for Fade In and Fade Out Animation with Alpha Effect
Animate Fade In Fade Out
UPDATED :
check this answer may this help you
I´ve been working in Kotlin (recommend to everyone), so the syntax might be a bit off.
What I do is to simply to call:
v.animate().alpha(0f).duration = 200
I think that, in Java, it would be the following.:
v.animate().alpha(0f).setDuration(200);
Try:
private void hide(View v, int duration) {
v.animate().alpha(0f).setDuration(duration);
}
private void show(View v, int duration) {
v.animate().alpha(1f).setDuration(duration);
}
According to the documentation AnimationSet
Represents a group of Animations that should be played together. The
transformation of each individual animation are composed together into
a single transform. If AnimationSet sets any properties that its
children also set (for example, duration or fillBefore), the values of
AnimationSet override the child values
AnimationSet mAnimationSet = new AnimationSet(false); //false means don't share interpolators
Pass true if all of the animations in this set should use the
interpolator associated with this AnimationSet. Pass false if each
animation should use its own interpolator.
ImageView imageView= (ImageView)findViewById(R.id.imageView);
Animation fadeInAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_in);
Animation fadeOutAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_out);
mAnimationSet.addAnimation(fadeInAnimation);
mAnimationSet.addAnimation(fadeOutAnimation);
imageView.startAnimation(mAnimationSet);
I hope this will help you.
we can simply use:
public void animStart(View view) {
if(count==0){
Log.d("count", String.valueOf(count));
i1.animate().alpha(0f).setDuration(2000);
i2.animate().alpha(1f).setDuration(2000);
count =1;
}
else if(count==1){
Log.d("count", String.valueOf(count));
count =0;
i2.animate().alpha(0f).setDuration(2000);
i1.animate().alpha(1f).setDuration(2000);
}
}
where i1 and i2 are defined in the onCreateView() as:
i1 = (ImageView)findViewById(R.id.firstImage);
i2 = (ImageView)findViewById(R.id.secondImage);
count is a class variable initilaized to 0.
The XML file is :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="#+id/secondImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="animStart"
android:src="#drawable/second" />
<ImageView
android:id="#+id/firstImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="animStart"
android:src="#drawable/first" />
</RelativeLayout>
#drawable/first and #drawable/second are the images in the drawable folder in res.
You can do this also in kotlin like this:
contentView.apply {
// Set the content view to 0% opacity but visible, so that it is visible
// (but fully transparent) during the animation.
alpha = 0f
visibility = View.VISIBLE
// Animate the content view to 100% opacity, and clear any animation
// listener set on the view.
animate()
.alpha(1f)
.setDuration(resources.getInteger(android.R.integer.config_mediumAnimTime).toLong())
.setListener(null)
}
read more about this in android docs
Please try the below code for repeated fade-out/fade-in animation
AlphaAnimation anim = new AlphaAnimation(1.0f, 0.3f);
anim.setRepeatCount(Animation.INFINITE);
anim.setRepeatMode(Animation.REVERSE);
anim.setDuration(300);
view.setAnimation(anim); // to start animation
view.setAnimation(null); // to stop animation
FOR FADE add this first line with your animation's object.
.animate().alpha(1).setDuration(2000);
FOR EXAMPLE
Today, I got stuck with this problem. This worked for me:
#JvmStatic
fun setFadeInFadeOutAnimation(v: View?) {
val fadeIn = ObjectAnimator.ofFloat(v, "alpha", 0.0f, 1f)
fadeIn.duration = 300
val fadeOut = ObjectAnimator.ofFloat(v, "alpha", 1f, 0.0f)
fadeOut.duration = 2000
fadeIn.addListener(object : AnimatorListenerAdapter(){
override fun onAnimationEnd(animation: Animator?) {
fadeOut.start()
}
})
fadeIn.start()
}
I am using a single Animator instance to smoothly scroll view down or right. First I set it up with common parameters within my custom View implementation:
private ObjectAnimator animator = new ObjectAnimator();
{
animator.setTarget(this);
animator.setDuration(moveDuration);
}
then I am using two methods to move down and right
public void moveRight() {
if( animator.isRunning() ) animator.end();
animator.setPropertyName("scrollX");
animator.setIntValues(getScrollX(), getScrollX() + cellWidth);
animator.start();
}
public void moveDown() {
if( animator.isRunning() ) animator.end();
animator.setPropertyName("scrollY");
animator.setIntValues(getScrollY(), getScrollY() + cellHeight);
animator.start();
}
I found, that only first called method works correctly. Another one works wrong as if first ran method left some traces inside animator object.
How to remove these traces and to reprogram animator from scrolling right to down and vice versa?
I had this issue too. For some reason, using setPropertyName() a second time doesn't seem to clear out the previous property and/or values.
Using setProperty() instead fixes this, e.g.:
Property<View, Float> mTranslationXProperty = Property.of(View.class,
Float.class, "translationX");
Property<View, Float> mScaleXProperty = Property.of(View.class,
Float.class, "scaleX");
...
animator.setProperty(mTranslationXProperty);
animator.setFloatValues(500f, 0f);
animator.start();
...
animator.setProperty(mScaleXProperty);
animator.setFloatValues(1f, 0f);
animator.start();
I was able to reset values using the code below:
final AnimatorSet animate = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.anim.anim_move);
List<Animator> animations = animate.getChildAnimations();
for (int i = 0; i < animations.size(); i++) {
ObjectAnimator animator = (ObjectAnimator) animations.get(i);
if (animator.getPropertyName().contentEquals("y")) {
animator.setFloatValues(0f, 500f);
}
}
animate.setTarget(starlightImageView);
animate.start();
I have created a 3D flip of a view using this android tutorial
However, I have done it programmatically and I would like to do it all in xml, if possible. I am not talking about simply shrinking a view to the middle and then back out, but an actual 3D flip.
Is this possible via xml?
Here is the answer, though it only works with 3.0 and above.
1) Create a new resources folder called "animator".
2) Create a new .xml file which I will call "flipping". Use the following xml code:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="0" android:valueTo="360" android:propertyName="rotationY" >
</objectAnimator>
No, the objectAnimator tags do not start with an uppercase "O".
3) Start the animation with the following code:
ObjectAnimator anim = (ObjectAnimator) AnimatorInflater.loadAnimator(mContext, R.animator.flipping);
anim.setTarget(A View Object reference goes here i.e. ImageView);
anim.setDuration(3000);
anim.start();
I got all this from here.
Since the answers to this question are fairly dated, here is a more modern solution relying on ValueAnimators.
This solution implements a true, visually appealing 3D-flip, because it not just flips the view, but also scales it while it is flipping (this is how Apple does it).
First we set up the ValueAnimator:
mFlipAnimator = ValueAnimator.ofFloat(0f, 1f);
mFlipAnimator.addUpdateListener(new FlipListener(frontView, backView));
And the corresponding update listener:
public class FlipListener implements ValueAnimator.AnimatorUpdateListener {
private final View mFrontView;
private final View mBackView;
private boolean mFlipped;
public FlipListener(final View front, final View back) {
this.mFrontView = front;
this.mBackView = back;
this.mBackView.setVisibility(View.GONE);
}
#Override
public void onAnimationUpdate(final ValueAnimator animation) {
final float value = animation.getAnimatedFraction();
final float scaleValue = 0.625f + (1.5f * (value - 0.5f) * (value - 0.5f));
if(value <= 0.5f){
this.mFrontView.setRotationY(180 * value);
this.mFrontView.setScaleX(scaleValue);
this.mFrontView.setScaleY(scaleValue);
if(mFlipped){
setStateFlipped(false);
}
} else {
this.mBackView.setRotationY(-180 * (1f- value));
this.mBackView.setScaleX(scaleValue);
this.mBackView.setScaleY(scaleValue);
if(!mFlipped){
setStateFlipped(true);
}
}
}
private void setStateFlipped(boolean flipped) {
mFlipped = flipped;
this.mFrontView.setVisibility(flipped ? View.GONE : View.VISIBLE);
this.mBackView.setVisibility(flipped ? View.VISIBLE : View.GONE);
}
}
That's it!
After this setup you can flip the views by calling
mFlipAnimator.start();
and reverse the flip by calling
mFlipAnimator.reverse();
If you want to check if the view is flipped, implement and call this function:
private boolean isFlipped() {
return mFlipAnimator.getAnimatedFraction() == 1;
}
You can also check if the view is currently flipping by implementing this method:
private boolean isFlipping() {
final float currentValue = mFlipAnimator.getAnimatedFraction();
return (currentValue < 1 && currentValue > 0);
}
You can combine the above functions to implement a nice function to toggle the flip, depending on if it is flipped or not:
private void toggleFlip() {
if(isFlipped()){
mFlipAnimator.reverse();
} else {
mFlipAnimator.start();
}
}
That's it! Simple and easy. Enjoy!
I have created a simple program for creating flip of view like :
In Activity you have to create this method, for adding flip_rotation in view.
private void applyRotation(View view)
{
final Flip3dAnimation rotation = new Flip3dAnimation(view);
rotation.applyPropertiesInRotation();
view.startAnimation(rotation);
}
for this, you have to copy main class used to provide flip_rotation.
import android.graphics.Camera;
import android.graphics.Matrix;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Transformation;
public class Flip3dAnimation extends Animation {
private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private Camera mCamera;
public Flip3dAnimation(View view) {
mFromDegrees = 0;
mToDegrees = 720;
mCenterX = view.getWidth() / 2.0f;
mCenterY = view.getHeight() / 2.0f;
}
#Override
public void initialize(int width, int height, int parentWidth,
int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
}
public void applyPropertiesInRotation()
{
this.setDuration(2000);
this.setFillAfter(true);
this.setInterpolator(new AccelerateInterpolator());
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float fromDegrees = mFromDegrees;
float degrees = fromDegrees
+ ((mToDegrees - fromDegrees) * interpolatedTime);
final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;
final Matrix matrix = t.getMatrix();
camera.save();
Log.e("Degree",""+degrees) ;
Log.e("centerX",""+centerX) ;
Log.e("centerY",""+centerY) ;
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}
The tutorial or the link by om252345 don't produce believable 3D flips. A simple rotation on the y-axis isn't what's done in iOS. The zoom effect is also needed to create that nice flip feel. For that, take a look at this example.
There is also a video here.
One of the better solution to flip the image with out use of the resource animation , is as follow:-
ObjectAnimator animation = ObjectAnimator.ofFloat(YOUR_IMAGEVIEW, "rotationY", 0.0f, 360f); // HERE 360 IS THE ANGLE OF ROTATE, YOU CAN USE 90, 180 IN PLACE OF IT, ACCORDING TO YOURS REQUIREMENT
animation.setDuration(500); // HERE 500 IS THE DURATION OF THE ANIMATION, YOU CAN INCREASE OR DECREASE ACCORDING TO YOURS REQUIREMENT
animation.setInterpolator(new AccelerateDecelerateInterpolator());
animation.start();
The simplest way to do it is using ViewPropertyAnimator
mImageView.animate().rotationY(360f);
Using the fluent interface you can build more complex and exciting animation.
E.g. you can enable hardware acceleration just call withLayer() method(API 16). More here
If you want to figure out how to create 3d flick animation, please follow here and here
I implemended my own solution only for a research. It includes: cancelation, accelleration, support API >= 15 and is based on Property Animation.
The entire animation includes 4 parts, 2 for each side.
Every objectAnimator has a listener that defines current animation index and represents an image in the onAnimationStart and current play time value in the onAnimationCancel.
It looks like
mQuarterAnim1.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
mQuarterCurrentAnimStartIndex = QUARTER_ANIM_INDEX_1;
mImageView.setImageResource(mResIdFrontCard);
}
#Override
public void onAnimationCancel(Animator animation) {
mQuarterCurrentAnimPlayTime = ((ObjectAnimator) animation).getCurrentPlayTime();
}
});
For start set call
mAnimatorSet.play(mQuarterAnim1).before(mQuarterAnim2)
If AnimatorSet was canceled we can calculate delta and run the reverse animation relying on the current index animation and the current play time value.
long degreeDelta = mQuarterCurrentAnimPlayTime * QUARTER_ROTATE / QUARTER_ANIM_DURATION;
if (mQuarterCurrentAnimStartIndex == QUARTER_ANIM_INDEX_1) {
mQuarterAnim4.setFloatValues(degreeDelta, QUARTER_FROM_1);
mQuarterAnim4.setDuration(mQuarterCurrentAnimPlayTime);
mAnimatorSet.play(mQuarterAnim4);
}
A full code snippet you can find here
Just put the view which you're going to animate it in place of viewToFlip.
ObjectAnimator flip = ObjectAnimator.ofFloat(viewToFlip, "rotationY", 0f, 360f); // or rotationX
flip.setDuration(2000); // 2 seconds
flip.start();
Adding to A. Steenbergen's great answer. When flipping the same view (updating a TextView for example) I removed the View.Visibility change in the constructor in order to keep the transition smoother.
public FlipListener(final View front, final View back) {
this.mFrontView = front;
this.mBackView = back;
}
I'm using an xml defined animation to slide a view off the screen. The problem is, as soon as the animation completes it resets to its original position. I need to know how to fix this. Here's the xml:
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="#android:anim/accelerate_interpolator">
<translate android:fromXDelta="0" android:toXDelta="-100%p" android:duration="500"/></set>
Here's the Java that I use to call it:
homeScrn = (View)findViewById(R.id.homescreen);
slideLeftOut = AnimationUtils.loadAnimation(this, R.anim.slide_left_out);
//Set Click Listeners For Menu
btnHelp.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
LayoutInflater.from(getApplicationContext()).inflate(R.layout.help, (ViewGroup)findViewById(R.id.subpage), true);
homeScrn.startAnimation(slideLeftOut);
}
});
So basically what happens is I inflate a view underneath one. Then I animate the view on top off to the left. As soon as it gets off screen and the animation is finished it resets its position back.
Finally got a way to work around,the right way to do this is setFillAfter(true),
if you want to define your animation in xml then you should do some thing like this
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/decelerate_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="0%"
android:toXDelta="-100%"
android:duration="1000"/>
</set>
you can see that i have defined filterAfter="true" in the set tag,if you try to define it in translate tag it won't work,might be a bug in the framework!!
and then in the Code
Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide_out);
someView.startAnimation(anim);
OR
TranslateAnimation animation = new TranslateAnimation(-90, 150, 0, 0);
animation.setFillAfter(true);
animation.setDuration(1800);
someView.startAnimation(animation);
then it will surely work!!
Now this is a bit tricky it seems like the view is actually move to the new position but actually the pixels of the view are moved,i.e your view is actually at its initial position but not visible,you can test it if have you some button or clickable view in your view(in my case in layout),to fix that you have to manually move your view/layout to the new position
public TranslateAnimation (float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
new TranslateAnimation(-90, 150, 0, 0);
now as we can see that our animation will starts from -90 x-axis to 150 x-axis
so what we do is set
someView.setAnimationListener(this);
and in
public void onAnimationEnd(Animation animation)
{
someView.layout(150, 0, someView.getWidth() + 150, someView.getHeight());
}
now let me explain public void layout (int left, int top, int right, int botton)
it moves your layout to new position first argument define the left,which we is 150,because translate animation has animated our view to 150 x-axis, top is 0 because we haven't animated y-axis,now in right we have done someView.getWidth() + 150 basically we get the width of our view and added 150 because we our left is now move to 150 x-axis to make the view width to its originall one, and bottom is equals to the height of our view.
I hope you people now understood the concept of translating, and still you have any questions you can ask right away in comment section,i feel pleasure to help :)
EDIT Don't use layout() method as it can be called by the framework when ever view is invalidated and your changes won't presist, use LayoutParams to set your layout parameters according to your requirement
The animations are working as expected. Just because you animated something does not mean you actually moved it. An animation only affects drawn pixels during the animation itself, not the configuration of the widgets.
You need to add an AnimationListener, and in the onAnimationEnd() method, do something that makes your move permanent (e.g., removes the view on top from its parent, marks the view on top as having visibility GONE).
I might be a bit late in replying, but I have the solution for this:
Just add android:fillAfter="true"
in your xml
You can use
fillAfter=true
fillEnabled=true
your View will'not reset to original position, but if you have some buttons or something else in your view , their position will not change.
You must use ObjectAnimator , it works from API 11 level . It changes View position automatic,
here is the example
ObjectAnimator objectAnimator= ObjectAnimator.ofFloat(mContent_container, "translationX", startX, endX);
objectAnimator.setDuration(1000);
objectAnimator.start();
Thanks JUL for his answer
If your app not found object animator, change the API level from Project -> properties -> Android , than import android.animation.ObjectAnimator;
Regards Hayk
You need to add this command:
final Animation animSlideLeft = new TranslateAnimation(0, -80, 0,-350, 0, 0, 0, 0);
animSlideLeft.setFillAfter(true);
I went to the same question and solved it with setting the marginLeft at OnAnimationEnd()..
MarginLayoutParams params = (MarginLayoutParams) this.getLayoutParams();
params.setMargins(this.getWidth()*position, 0,0,0);
this.setLayoutParams(params);
This problem has bothered for more than a week.
And Muhammad's answer pointed me a strightforward way to solve it.
I used sever layout to implement side menus with animation.
"view.layout will not be persistent. You should use LayoutParams, which will be persistent."
Here's my solution:
(Use what kind of LayoutParameter is depended on your own parent's layout):
#Override
public void onAnimationEnd(Animation animation) {
FrameLayout.LayoutParams layoutParams=new FrameLayout.LayoutParams(screenWidth, screenHeight);
layoutParams.setMargins((int) -(screenWidth * RATE), 0,
(int) (screenWidth - screenWidth * RATE), screenHeight);
for(View v:views) {
v.setLayoutParams(layoutParams);
//v.layout((int) -(screenWidth * RATE), 0, (int) (screenWidth - screenWidth * RATE), screenHeight);
v.clearAnimation();
}
}
fillAfter = true will do the job to transform view to new animation positon.
rotateAnimation.fillAfter = true;
If anybody interested to move arrow_up & arrow_down animations for a recycle view expands/collapse behavior.
Initial state: Collapse
call the method with a child visibility flag(View.VISIBLE/View.GONE).
Below is code belongs to animations.
fun setArrowImage(imageView: ImageView, childVisibility: Int) {
val angleRange = if (childVisibility == View.VISIBLE) Pair(0F, 180F) else
Pair(100f, 0F)
val rotateAnimation = RotateAnimation(
angleRange.first, angleRange.second,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
)
rotateAnimation.duration = 300
rotateAnimation.fillAfter = true;
imageView.startAnimation(rotateAnimation)
}
Use helper methods below to easily animate your view. Then you can animate and reset after completion like this:
// Animate the view:
fly(
view1,
(float) 0,
(float) 0,
(float) 0,
(float) 1000,
250,
null,
null,
() -> {
// Return the view to initial position on animation end:
fly(
view1,
(float) 0,
(float) 0,
(float) 0,
(float) 0,
0);
return null;
});
Helper methods:
/**
* Translation of a view.
*/
public static void fly(
View view,
float fromXDelta,
float toXDelta,
float fromYDelta,
float toYDelta,
int duration) {
fly(
view,
fromXDelta,
toXDelta,
fromYDelta,
toYDelta,
duration,
null,
null,
null);
}
/**
* Translation of a view with handlers.
*
* #param view A view to animate.
* #param fromXDelta Amount to shift by X axis for start position.
* #param toXDelta Amount to shift by X axis for end position.
* #param fromYDelta Amount to shift by Y axis for start position.
* #param toYDelta Amount to shift by Y axis for end position.
* #param duration Animation duration.
* #param start On animation start. Otherwise NULL.
* #param repeat On animation repeat. Otherwise NULL.
* #param end On animation end. Otherwise NULL.
*/
public static void fly(
View view,
float fromXDelta,
float toXDelta,
float fromYDelta,
float toYDelta,
int duration,
Callable start,
Callable repeat,
Callable end) {
Animation animation;
animation =
new TranslateAnimation(
fromXDelta,
toXDelta,
fromYDelta,
toYDelta);
animation.setDuration(
duration);
animation.setInterpolator(
new DecelerateInterpolator());
animation.setFillAfter(true);
view.startAnimation(
animation);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
if (start != null) {
try {
start.call();
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onAnimationEnd(Animation animation) {
if (end != null) {
try {
end.call();
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onAnimationRepeat(
Animation animation) {
if (repeat != null) {
try {
repeat.call();
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
Nothing from answers worked with me; although #Muhammad Babar answer inspired me to get a solution:
He mentioned that we can layout the view to the new position upon animation end:
public void onAnimationEnd(Animation animation) {
someView.layout(150, 0, someView.getWidth() + 150, someView.getHeight());
}
Although this didn't work with me instead; I had to do that in a Handler with delayed Runnable using a delay value that is slightly less than the animation duration.
So, in my case the animation duration is 500 msec, and I used a handler on 450 mesec, so it gets triggered just before the animation ends by 50 msec.
Handler().postDelayed({
someView.layout(150, 0, someView.width + 150, someView.hight)
someView.requestLayout()
someView.forceLayout()
}, 450)