如何实现片段删除动画

40
我想要为片段的移除添加动画效果。
我尝试过:
getSupportFragmentManager().beginTransaction()
    .setCustomAnimations(R.anim.push_down_in, R.anim.push_up_out)
    .remove(myFragment)
    .commit();

但是这个片段只是消失了。

我注意到离开动画仅在使用“replace”时播放,所以我尝试将该片段替换为空片段,如下:

getSupportFragmentManager()
    .beginTransaction()
    .setCustomAnimations(R.anim.push_down_in, R.anim.push_up_out)
    .replace(viewId, new Fragment())
.commit();

但它仍然只是消失了消失了。

那么,我如何使片段的移除有动画效果?

13个回答

21

当我遇到类似问题时,我看到了这个,并想简单地写下几句话。

与其创建一个虚拟片段来替换现有的片段,我认为您应该对当前片段的视图进行动画处理。当动画完成后,您可以简单地移除该片段。

这是我的做法:

final FragmentActivity a = getSherlockActivity();

if (a != null) {
    //Your animation
    Animation animation = AnimationUtils.loadAnimation(a, R.anim.bottom_out);
    animation.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime));

    //You can use AnimationListener, MagicAnimationListener is simply a class extending it.
    animation.setAnimationListener(new MagicAnimationListener() {
        @Override
        public void onAnimationEnd(Animation animation) {
            //This is the key, when the animation is finished, remove the fragment.
            try {
                FragmentTransaction ft = a.getSupportFragmentManager().beginTransaction();
                ft.remove(RestTimerFragment.this);
                ft.commitAllowingStateLoss();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });

    //Start the animation.  
    getView().startAnimation(animation);
}

但是你在哪里做到了这个?在片段的哪个方法中? - 4gus71n
1
无论您想删除片段的地方在哪里。例如,当计时器达到0或用户按丢弃时,我就这样做了。 - zoltish
你可以这样做,但如果你想在后退按钮按下时倒放动画呢? - Archie G. Quiñones
拥有片段动画的意义在于您无需为视图进行动画处理。 - Greg Ennis
2
读到2020年的SherlockActivity,我不禁露出了灿烂的微笑。好旧的时光 :-) - A.D.
@A.D.,哈哈哈。 :) - CoolMind

19

我想通了。

正在退出的视图在进入视图的画布上进行动画处理,因此如果没有进入画布,则没有用于动画的画布。

为了显示动画,我必须始终使用replace并使用与正在退出的碎片相同大小的进入碎片。 动画完成后,我将新碎片的视图设置为gone。


我很想听更多关于这个的内容。我想要动画地移除几个片段,然后在一段时间后(异步任务处理)再动画地添加另一组片段。我可以简单地创建一个“虚拟”的片段,其透明视图与我想要动画移除的原始片段大小相同吗? - Dan Devine
是的,那正是我所做的。 - hugoc
还有其他解决方案吗? - Archie G. Quiñones

14

您可以通过将自定义动画设置为fragmentTransaction来使移除过程有动画效果。

        fragmentTransaction.setCustomAnimations(R.anim.right_in, R.anim.defff,R.anim.defff,R.anim.right_out);
第三个和第四个参数用于删除片段。

2

我从Zoltish的回答中得到了灵感,这是我的实现:

1.在片段内添加此方法,它将使片段向左动画移出屏幕:

public void animateOut()
{
    TranslateAnimation trans=new TranslateAnimation(0,-300*Utils.getDensity(getActivity()), 0,0);
    trans.setDuration(150);
    trans.setAnimationListener(new Animation.AnimationListener() {

        @Override
        public void onAnimationStart(Animation animation) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            // TODO Auto-generated method stub
            ((BetsActivty)getActivity()).removeFrontFragmentAndSetControllToBetting();
        }
    });
    getView().startAnimation(trans);
}

在onAnimationEnd()方法中删除片段的方法如下:
getSupportFragmentManager().beginTransaction().
        remove(getSupportFragmentManager().findFragmentById(R.id.fragment_container)).commit();

2. 在activity的onBack()方法中调用片段的animateOut。

祝好

顺便说一下,我的getDensity()是:

public static int getDensity(Context context)
{
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    return (int)metrics.density;
}

使用它,我为当前正在运行的设备计算 DP 值。


OnAnimationEnd() 函数出现问题 https://dev59.com/A2035IYBdhLWcg3wW-pa - Kurovsky

2

在下一个片段插入点之前用一个空的片段替换,同时延迟下一个片段的插入(200毫秒),以便空白片段的退出动画可以播放,解决了我的问题。

这是插入带有退出动画的空片段的代码。

getSupportFragmentManager()
                        .beginTransaction()
                        .setCustomAnimations(R.anim.exit, R.anim.pop_exit)
                        .replace(R.id.fragmentLayout, new Fragment())
                        .commit();

Exit.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="-100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="200"/>

</set>

pop_exit.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="200"/>

</set>

2

下面是一个简单的解决方案:

1-在fragment.getView()上调用animate。

2-在onAnimationEnd()中删除fragment。

final Fragment frag= getSupportFragmentManager().findFragmentById(R.id.fragmentContainer);
        frag.getView().animate().alpha(0f).scaleX(0f).scaleY(0f)

                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                        getSupportFragmentManager()
                                .beginTransaction()
                                .remove(frag)
                                .commit();
                    }
                }).start();

2

我同意hugoc的观点,这里提供一些代码来解决它

public class MyActivity extends Activity {
    //Some thing
    public void Fragment2BackToFragment1(Fragment fragment1, Fragment fragment2) {
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction ft = manager.beginTransaction();
        animateExit(fragment2);
        ft.replace(R.id.main_content, fragment1, "fragment1");
        ft.commit();
    }
    private void animateExit(Fragment exitFragment) {
        if (exitFragment != null) {
            final View view = exitFragment.getView();
            if (view != null) {
                int anim = R.anim.fade_out;
                Animation animation =
                    AnimationUtils.loadAnimation(getActivity(), anim);
                animation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {

                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        view.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                view.setVisibility(View.GONE);
                            }
                        }, 300);
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {


                    }
                });
                view.startAnimation(animation);
            }
        }
    }
}

1

如@hugoc所说的那样,原因是:

正在退出的视图在进入视图的画布上进行动画处理,因此如果没有进入画布,则没有用于动画的画布。

为了显示动画,我必须始终使用replace并使用与退出片段相同大小的进入片段。 动画完成后,我将新片段的视图设置为gone。

下面是实际代码:

FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction transaction = manager.beginTransaction();
    transaction.setCustomAnimations(R.anim.slide_in_bottom, R.anim.slide_out_top);
    transaction.hide(removeFragment).add(R.id.fragment_container,addFragment).commit();
    transaction = manager.beginTransaction();
    transaction.remove(removeFragment).commit();

0

仅仅因为我花了时间并且喜欢我的扩展函数:(Kotlin)

fun FragmentManager.removeByTagAnimated(tag: String, animation: Int){
    findFragmentByTag(tag)?.let { fragToRemove ->
        val anim = AnimationUtils.loadAnimation(fragToRemove.context, animation).apply {
            setAnimationListener(object : Animation.AnimationListener {
                override fun onAnimationStart(animation: Animation?) {}
                override fun onAnimationRepeat(animation: Animation?) {}

                override fun onAnimationEnd(animation: Animation?) {
                    commit {
                        remove(fragToRemove)
                    }
                }
            })
        }
        fragToRemove.view?.startAnimation(anim)
    }
}

动画是一个像这个页面中的R.anim资源。

在你的Activity中,只需使用supportFragmentManager.removeByTagAnimated(MY_FRAGMENT_TAG, R.anim.my_exit_animation)


0

所以简单的方法是:

当您打开一个片段(从父活动调用)时:

    FragmentA fragment = new FragmentA();
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.setCustomAnimations(R.anim.slide_up, R.anim.slide_down);
    transaction.add(android.R.id.content, fragment);
    transaction.addToBackStack(null);
    transaction.commit();

指定输入和输出事务

transaction.setCustomAnimations(R.anim.slide_up, R.anim.slide_down);

关闭片段时(从片段内部调用)

getActivity().getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.slide_up, R.anim.slide_down).remove(this).commit();

指定输入和输出交易

setCustomAnimations(R.anim.slide_up, R.anim.slide_down)


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