简体   繁体   English

带有翻译动画的Android View-定位无法正常工作

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

I have a View that has an OnClickListener . 我有一个具有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. 经过一番排查后,我发现我的View的getTop()方法返回了相同的值-即使在平移动画将视图移动到屏幕的不同部分之后也是如此。 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. 我正在做的一些事情:我使用的是ObjectAnimation类而不是TranslationAnimation类,因为我想保持OnClickListener功能。 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. 使用TranslationAnimation类,我发现视图已正确移动,但是OnClickListener仅在View所在的区域中工作。 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. 使用ObjectAnimation类,我可以轻松地使翻译正常工作,并且OnClickListener功能正确-在屏幕上当前视图的位置触发它。

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. 它沿Y轴向上平移,其中的偏移量确定了View需要从其当前位置移动多远。

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. 这就是一切的地方child.getTop()返回视图原始位置的Y坐标。 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. 我读了一个不同的问题,该问题表明我应该改用child.getY() ,这应该使我获得translationY位置加上top位置,但这并没有带来更好的结果。 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: System.out的输出如下所示:

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. 因此,在动画完成并设置新位置后调用child.getTop()返回一个正整数,但是视图实际上并没有完全显示在屏幕上。 It is above the screen, partly visible. 它在屏幕上方,部分可见。 The height of the view itself is about 700px. 视图本身的高度约为700像素。 I am still so confused as to why this is such a hard thing to accomplish. 我仍然很困惑为什么这很难完成。

EDIT 2 编辑2

I have also tried setting layoutparams inside the onAnimationEnd method: 我也尝试过在onAnimationEnd方法中设置layoutparams:

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. 结果: child.getTop()仍返回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 : 但您可能希望它减去LinearLayout的高度,否则LinearLayout会被底部截断:

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 : 然后使用ViewPropertyAnimator对LL进行动画处理,如下所示:

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.getHeight()返回0,则系统尚未完成线性布局的设置,在这种情况下,您可能需要执行以下操作:

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. 请记住,250毫秒的持续时间非常快,通常不会在屏幕上平移翻译内容,因此您可能需要将其设置得更高一些,但这仅是口味问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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