简体   繁体   中英

Android View with a translate animation - positioning is not working as expected

I have a View that has an OnClickListener . When clicked, the view translates up to a certain position on the page. This is no problem, the view goes where it should. When the view is clicked again, I would like to position it somewhere else, but this is not the case. After a little bit of trouble shooting, I found that my View's getTop() method returns the same value - even after the translation animation has moved the view to a different part of the screen. For the second animation, it is not using the current position (as I would expect), it instead uses the initial position.

Few things that I am doing: I am using the ObjectAnimation class rather than the TranslationAnimation class, since I wanted to keep the OnClickListener functioning. With the TranslationAnimation class, I found that the view was correctly moved, but the OnClickListener was only working in the area that the View started from. Using the ObjectAnimation class, I was able to easily get the translation to work AND the OnClickListener functions correctly - it is triggered where the view currently is on the screen.

Here's what I have so far:

final LinearLayout child = layouts.get(i); //ArrayList containing some dynamic layouts
final int offset = target - child.getTop(); 
ObjectAnimator anim = ObjectAnimator.ofFloat(child,"translationY",offset);
anim.setDuration(250);
anim.start();

This is what happens when the view is clicked the first time. It translates up along the Y axis, where the offset determines how far the View needs to move from its current position.

Now, here's what happens on the second click. The goal here was to align the view with the parent's base.

target = parent.getBottom();
offset = target - child.getTop();
anim = ObjectAnimator.ofFloat(child, "translationY",offset);
anim.setDuration(250);
anim.start();
prev = child;

This is where things fall apart - child.getTop() returns the Y coordinate of the view's ORIGINAL position. Not the current position. So after the animation, the view is placed well below the bottom of the parent. I read a different question which stated that I should use child.getY() instead, which is supposed to give me the translationY position plus the top position, but this didn't lead to any better results. I can't seem to get this to work just right. I'd simply like to move the view from its current position to the bottom of the screen, but this appears to be a hard thing to accomplish. Any help would be appreciated.

EDIT

I have added an animation listener:

ObjectAnimator anim = ObjectAnimator.ofFloat(child,"translationY",offset);
anim.setDuration(250);
anim.addListener(new ObjectAnimator.AnimatorListener(){
    @Override
    public void onAnimationStart(Animator animation) {
        System.out.println("start: " + child.getTop() + " " + child.getY());
    }

    @Override
    public void onAnimationEnd(Animator animation) {
        System.out.println("end: " + child.getTop() + " " + child.getY() + " " + child.getTranslationY());
        child.setTop((int)child.getY());
        System.out.println(child.getTop());
    }

    @Override
    public void onAnimationCancel(Animator animation) {}

    @Override
    public void onAnimationRepeat(Animator animation) {}
});
anim.start();

Here I am setting the listener to try to change where the Top of the view is located. Behaviour is again not working as expected. The view is actually sent up above the screen when I do this. Output of the System.out looks like this:

start: 2008 2008.0
end: 2008 478.0 -1530.0
478

So calling child.getTop() after the animation is complete and setting a new position returns a positive integer, but the view is not actually completely on screen. It is above the screen, partly visible. The height of the view itself is about 700px. I am still so confused as to why this is such a hard thing to accomplish.

EDIT 2

I have also tried setting layoutparams inside the onAnimationEnd method:

RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)child.getLayoutParams();
params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
params.topMargin = (int)child.getY();
child.setLayoutParams(params);

Result: child.getTop() still returns the original position of 2008.

You can get the very bottom of the screen coordinates like this :

float bottomOfScreen = getResources().getDisplayMetrics().heightPixels;

but you probably want it minus the height of your LinearLayout or else your LinearLayout will be cut off by the bottom :

float bottomOfScreen = getResources().getDisplayMetrics().heightPixels
                    - child.getHeight();

 // if you want a little more space to the bottom
    // try something like - child.getHeight()*2; 

Then use ViewPropertyAnimator to animate your LL like this :

child.animate()
    .translationY(bottomOfScreen)
    .setInterpolator(new AccelerateDecelerateInterpolator())
    .setDuration(250);

The Interpolator is just to make the animation more realistic.

In the case that child.getHeight() returns 0 , your Linear Layout has not been finished setting up by the system, in that case you might want to do something like :

child.post(new Runnable() {
        @Override
        public void run() {
            float bottomOfScreen = getResources().getDisplayMetrics().heightPixels
                    - child.getHeight()*2;
            child.animate()
                    .translationY(bottomOfScreen)
                    .setInterpolator(new AccelerateDecelerateInterpolator())
                    .setDuration(250);
        }
    });

Remember that a duration of 250 milliseconds is very fast, and does usually not look cool translating stuff on the screen, so you might want to set it a little higher, but thats just a matter of taste.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM