44

I have android translate Animation. I have an ImageView with random generated position (next1, next2). I am calling void every 3 seconds. It generates new position of the View and then make animation and move View to destination position. Translate animation has AnimationListener implemented. When the animation finish, I move View permanently to the new position (in OnAnimationEnd). My problem is that animation position does not correspond with setting layoutParams positions. When animation end, it makes jump to a new position, which is about 50-100 pixels far. I think the positions should be the same because I use same values (next1, next2) in both situations. Please can you show me the way to find sollution ? Drawing of situation here here

 FrameLayout.LayoutParams pozice_motyl = (FrameLayout.LayoutParams)  pozadi_motyl.getLayoutParams();    
            TranslateAnimation anim = new TranslateAnimation(Animation.ABSOLUTE,pozice_motyl.leftMargin, Animation.ABSOLUTE, next1, Animation.ABSOLUTE, pozice_motyl.topMargin, Animation.ABSOLUTE, next2);
            anim.setDuration(1000);
            anim.setFillAfter(true);
            anim.setFillEnabled(true);

            anim.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {




                    FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(100, 100);

                    layoutParams.leftMargin = (int)(next1);
                    layoutParams.topMargin = (int)(next2);
                    pozadi_motyl.setLayoutParams(layoutParams);

                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });

            pozadi_motyl.startAnimation(anim);

Here is XML layout:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:id="@+id/pozadi0"
    android:gravity="center_vertical"
    android:layout_gravity="center_vertical"          
    android:background="@drawable/pozadi2"
    >



<LinearLayout
android:id="@+id/pozadi_motyl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        >

  <ImageView android:id="@+id/obrazek_motyl"
             android:src="@drawable/motyl"
             android:layout_width="100dip"
             android:layout_height="100dip"
                         />

   </LinearLayout>


<LinearLayout 
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>

<RelativeLayout
android:id="@+id/obrazek_pozadi0"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>



 <ImageView android:id="@+id/zaba_obrazek0"
android:src="@drawable/zaba_obrazek"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerInParent="true"
/>

</RelativeLayout>   
</LinearLayout> 

<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" 
>

<cz.zaba.Spojnice  
android:layout_width="fill_parent"          
android:layout_height="fill_parent" 
/>

</LinearLayout>
</FrameLayout>
JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
mira
  • 1,056
  • 3
  • 15
  • 32

7 Answers7

57

I usually prefer to work with deltas in translate animation, since it avoids a lot of confusion.

Try this out, see if it works for you:

TranslateAnimation anim = new TranslateAnimation(0, amountToMoveRight, 0, amountToMoveDown);
anim.setDuration(1000);

anim.setAnimationListener(new TranslateAnimation.AnimationListener() {

    @Override
    public void onAnimationStart(Animation animation) { }

    @Override
    public void onAnimationRepeat(Animation animation) { }

    @Override
    public void onAnimationEnd(Animation animation) 
    {
        FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)view.getLayoutParams();
        params.topMargin += amountToMoveDown;
        params.leftMargin += amountToMoveRight;
        view.setLayoutParams(params);
    }
});

view.startAnimation(anim);

Make sure to make amountToMoveRight / amountToMoveDown final

Hope this helps :)

Sufian
  • 6,405
  • 16
  • 66
  • 120
Gil Moshayof
  • 16,633
  • 4
  • 47
  • 58
  • 2
    Thanks Gil. Minor correction: TranslateAnimation anim = new TranslateAnimation(0, amountToMoveRight, 0, amountToMoveDown); – Srikanth Jan 05 '14 at 11:47
  • 7
    This causes a flicker, see: http://stackoverflow.com/questions/2650351/android-translateanimation-resets-after-animation – Saro Taşciyan Feb 27 '14 at 13:18
  • 11
    no need to add listener, just use setFillAfter(true) – Valera Sep 12 '14 at 09:17
  • 2
    @Valera doing this will cause unexpected behaviour when trying to intercept touch events on the animated view – Gil Moshayof Dec 09 '14 at 13:49
  • For some reason I needed to put the body of `onAnimationEnd()` in a handler. I don't know why but a `handler.post()` worked, otherwise I'd see a little jerkiness at the end of animation. – Sufian Aug 07 '17 at 12:47
49

You should rather use ViewPropertyAnimator. This animates the view to its future position and you don't need to force any layout params on the view after the animation ends. And it's rather simple.

myView.animate().x(50f).y(100f);

myView.animate().translateX(pixelInScreen) 

Note: This pixel is not relative to the view. This pixel is the pixel position in the screen.

bpr10
  • 1,086
  • 8
  • 14
  • any way to set a listener? – the_prole Mar 04 '20 at 21:49
  • @the_prole mView.animate().translationY(pixelInScreen) .setListener(object : Animator.AnimatorListener { override fun onAnimationStart(animation: Animator?) {} override fun onAnimationEnd(animation: Animator?) { slideIn(binding.bottomTextContainer) } override fun onAnimationCancel(animation: Animator?) {} override fun onAnimationRepeat(animation: Animator?) {} }) – Ankit Pandey Apr 21 '22 at 12:37
12

Just Do like this

view.animate()
            .translationY(-((root.height - (view.height)) / 2).toFloat())
            .setInterpolator(AccelerateInterpolator()).duration = 1500

Here, view is your View which is animating from its origin position. root is root View of your XML file.

Calculation inside translationY is made for moving your view to the top but keeping it inside the screen, otherwise, it will go partially outside of the screen if you keep its value 0.

Kishan Solanki
  • 13,761
  • 4
  • 85
  • 82
Rushi Ayyappa
  • 2,708
  • 2
  • 16
  • 32
2

This is what worked for me perfectly:-

// slide the view from its current position to below itself
public void slideUp(final View view, final View llDomestic){

    ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationY",0f);
    animation.setDuration(100);
    llDomestic.setVisibility(View.GONE);
    animation.start();

}

// slide the view from below itself to the current position
public void slideDown(View view,View llDomestic){
    llDomestic.setVisibility(View.VISIBLE);
    ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationY",   0f);
    animation.setDuration(100);
    animation.start();
}

llDomestic : The view which you want to hide. view: The view which you want to move down or up.

Debasish Ghosh
  • 1,867
  • 20
  • 29
2

You can try this way -

ObjectAnimator.ofFloat(view, "translationX", 100f).apply {
    duration = 2000
    start()
}

Note - view is your view where you want animation.

Bajrang Hudda
  • 3,028
  • 1
  • 36
  • 63
1

Listing down 3 ways to achieve this for future reference

fun translateView(viewToAnimate: View, positionX: Int) {
        

Animate View directly

        viewToAnimate.animate()
            .x(positionX)
            .setDuration(600L)
            .setInterpolator(defaultAnimationInterpolator)
            .start()

Object Animator

         ObjectAnimator.ofFloat(
            viewToAnimate,
            View.X,
            positionX
        ).apply {
            duration = 600
            interpolator = defaultAnimationInterpolator
        }.start()

Value Animator

        ValueAnimator.ofFloat(viewToAnimate.x, positionX).apply {
            duration = 2000
            interpolator = defaultAnimationInterpolator
            addUpdateListener {
                viewToAnimate.x = it.animatedValue as Float
            }
            start()
        }
    }
Hitesh Sahu
  • 41,955
  • 17
  • 205
  • 154
-1
Just add this function. And we are good to goo.. 


fun moveView(viewToMove: View, targetView: View, repeatCount: Int? = 10) {
    val viewToMovePos = IntArray(2)
    viewToMove.getLocationOnScreen(viewToMovePos)

    val targetViewPos = IntArray(2)
    targetView.getLocationOnScreen(targetViewPos)

    // Calculate the distance to move
    val moveX = targetViewPos[0] - viewToMovePos[0]
    val moveY = targetViewPos[1] - viewToMovePos[1]

    // Create a TranslateAnimation for the movement
    val animation = TranslateAnimation(0f, moveX.toFloat(), 0f, moveY.toFloat())
    animation.duration = 300 // Set the duration of the animation (in milliseconds)

    // Set animation properties (optional)
    animation.fillAfter = true
    animation.repeatCount = repeatCount ?: 10


    // Start the animation on the source view
    viewToMove.startAnimation(animation)
}