TranslateAnimation - 动画仅在第二次之后起作用

3

我使用了一些找到的代码来制作一个滑动面板,基本上它可以工作,但有一个小问题。

第一次打开面板时,动画不起作用。

以下是动画的代码:

    TranslateAnimation anim = null;


    m_isOpen = !m_isOpen;

    if (m_isOpen) {
        setVisibility(View.VISIBLE);
        anim = new TranslateAnimation(0.0f, 0.0f, getHeight(), 0.0f);
    } else {
        anim = new TranslateAnimation(0.0f, 0.0f, 0.0f, getHeight());
        anim.setAnimationListener(new Animation.AnimationListener() {
              public void onAnimationEnd(Animation animation) {
                   setVisibility(View.GONE);
              }

              public void onAnimationRepeat(Animation animation) {
                   // not needed
              }

              public void onAnimationStart(Animation animation) {
                   // not needed
              }
        });

    }

    anim.setDuration(300);
    anim.setInterpolator(new AccelerateInterpolator(1.0f));
    startAnimation(anim);

为什么当我打开面板时,第一个面板没有动画,但其他所有面板都有呢?


你确定它不起作用吗?尝试调试它或者加一些日志。也许是因为你的面板还没有可见或者正在创建视图时才开始工作的? - ania
它不起作用。只有在第一次打开后,动画才能同时适用于打开和关闭。 - piojo
我找到了一种解决方案:不是将面板的可见性设置为GONE,而是在应用程序启动时关闭面板。 - piojo
4个回答

6

你是在什么时候调用这个方法?可能只有在“第一次”之后才会执行,因为当你第一次调用它时面板还没有被渲染,getHeight() 返回0。尝试等待 getHeight() 有值后再开始动画。你也可以尝试将该值硬编码为某个值,以测试我的理论是否正确。


你是对的。我尝试使用 getMeasuredHeight(),本以为它会给出渲染前的高度,但显然不是这样。有比我在上面评论中写的更好的解决方案吗? - piojo
我认为唯一的解决方案是将动画设置为固定数字,而不是使用“getHeight”。 - piojo
因为“尝试等待直到getHeight()有值”在你提出如何等待的解决方案之前是没有意义的,所以被踩了。 - Aleks N.
1
等待组件准备好的最简单方法是使用 post 方法。 - dmon
只是为了阐述dmon所说的,如果在XML中将高度设置为特定值,则可以使用以下代码获取它:`int theLayoutHeight = theView.getLayoutParams().height; if (theLayoutHeight > 0) { theViewHeight = theLayoutHeight; }` - dazed
显示剩余3条评论

0

你可以使用延迟函数来完成它

 TranslateAnimation animate1 = new TranslateAnimation(
                    0,                 // fromXDelta
                    0,                 // toXDelta
                    0,  // fromYDelta
                    binding.saveCardview.getMeasuredHeight());                // toYDelta
                animate1.setDuration(500);
                animate1.setFillAfter(true);
                binding.saveCardview.startAnimation(animate1);

                final Handler handler = new Handler(Looper.getMainLooper());
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //Do something after 100ms
                        binding.saveCardview.setVisibility(View.GONE);
                        TranslateAnimation animate2 = new TranslateAnimation(
                                0,                 // fromXDelta
                                0,                 // toXDelta
                                binding.carCardview.getHeight(),  // fromYDelta
                                0);                // toYDelta
                        animate2.setDuration(1000);
                        animate2.setFillAfter(true);
                        binding.carCardview.startAnimation(animate2);
                    }
                }, 500);

0
如果您只想要动画一个视图,那么您可以像下面这样在XML中编写动画:
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromYDelta="-100%"
        (or)    
android:toYDelta="-100%"  
android:duration="300"/>

这样,你就不需要使用getHeight()了。Java代码部分如下:

    final View flashTitle = findViewById(R.id.flash_title);
    Animation slideDownOnscreen = AnimationUtils.loadAnimation
            (this,  R.anim.slide_down_onscreen);
    flashTitle.setAnimation(slideDownOnscreen);
    flashTitle.setVisibility(View.VISIBLE);

或者,如果您需要同时动画化多个视图,请使用第一个视图执行上述操作,并在post runnable中动画化后续视图,以便getHeight()返回第一个视图的正确高度,如下所示:

    flashTitle.post(new Runnable() {
        @Override
        public void run() {
            System.out.println("NOTE    flashTitle height: "+flashTitle.getHeight());
            Animation slideDown = new TranslateAnimation(0, 0,
                    -flashTitle.getHeight(),0);
            slideDown.setDuration(300);
            flashLine.setVisibility(View.VISIBLE);
            flashLine.startAnimation(slideDown);
            //(or)flashLine.animate().translationYBy(flashTitle.getHeight()).setDuration(300);
        }
    });

您还需要将accelerate_interpolator添加为Android的默认插值器,因为其默认值是accelerate_decelerate_interpolator


如果您还需要将当前可见的视图移出路径,您需要在onCreate()中计算高度。请参考此答案 - willlma

0

我让那段代码工作的方式:


final ViewGroup viewGroup = (ViewGroup) findViewById(R.id.panel);
viewGroup.setVisibility(View.VISIBLE);
final ViewTreeObserver treeObserver = viewGroup.getViewTreeObserver();

if (treeObserver.isAlive()) {
    final OnPreDrawListener l = new OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            treeObserver.removeOnPreDrawListener(this);
            TranslateAnimation anim = new TranslateAnimation(0.0f, 0.0f, viewGroup.getHeight(), 0.0f);
            anim.setDuration(1000);
            anim.setInterpolator(new AccelerateInterpolator(1.0f));
            viewGroup.startAnimation(anim);

            return false;
            }
        };
    treeObserver.addOnPreDrawListener(l);
}

这就是它的本质。希望能有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接