执行操作后片段事务动画完成

59

我希望在动画完成后设置按钮的可见性。

这是调用动画的代码:

android.support.v4.app.FragmentTransaction fAnimation = this.getActivity().getSupportFragmentManager().beginTransaction();
fAnimation.setCustomAnimations(android.R.anim.slide_in_left, R.anim.pull_out_to_left);
if (this.isVisible()) {
    fAnimation.hide(this);
    fAnimation.commit();
}

// code that will be executed when the fragment is gone (after the animation is over)

有没有办法添加监听器以了解我的片段何时消失?

5个回答

70

@nmw在他的回答中实现的动画器是在API Level 11中添加的,无法与Android支持库实现的Fragment一起使用。

为了监听Fragment动画事件,我扩展了支持库中的Fragment类,并重写了onCreateAnimation方法,将自定义的AnimationListener附加到返回的Animation对象上:

public class MyFragment extends android.support.v4.app.Fragment {

    private static final String TAG = "MyFragment";

    @Override
    public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {

        Animation anim = AnimationUtils.loadAnimation(getActivity(), nextAnim);

        anim.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
                Log.d(TAG, "Animation started.");
                // additional functionality 
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                Log.d(TAG, "Animation repeating.");
                // additional functionality
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                Log.d(TAG, "Animation ended.");
                // additional functionality
            }
        });

        return anim;
    }
}

8
当 enter 为 false 时,监听器不会被调用,因为 FragmentManagerImpl 设置了自己的监听器。将其包装在 AnimationSet 中返回可以解决问题。 - sergio91pt
@sergio91pt,你能解释一下怎么做吗? - Aman Alam
7
只需创建一个新的AnimationSet,并添加具有已设置监听器的动画,然后返回该集即可。这样可以让FragmentManagerImpl在不覆盖您自己的监听器的情况下设置另一个监听器。 - sergio91pt
3
这个怎么用?我使用了这段代码,动画在闪烁一下后就回到了原始屏幕并开始正常播放动画。我的代码是:Animation anim = AnimationUtils.loadAnimation(getActivity(), nextAnim); AnimationSet animationWrapper = new AnimationSet(false); animationWrapper.addAnimation(anim); … return animationWrapper; - Merk
1
您可以通过@Merk方法,在进入时返回“animation”,在退出时返回“animation set”来避免闪烁。 - Alberto Méndez
显示剩余7条评论

16
你需要继承Fragment类并覆盖onCreateAnimator方法,然后就可以从XML文件中加载动画并添加监听器。
例如:
public class MyFragment extends Fragment
{
    @Override
    public Animator onCreateAnimator(int transit, boolean enter, int nextAnim)
    {
        final int animatorId = (enter) ? R.anim.in_anim : R.anim.out_anim;
        final Animator anim = AnimatorInflater.loadAnimator(getActivity(), animatorId);
        anim.addListener(new AnimatorListenerAdapter()
        {
            @Override
            public void onAnimationStart(Animator animation)
            {
                ...
            }

            @Override
            public void onAnimationEnd(Animator animation)
            {
               ...
            }
        });

        return anim;
   }    

我尝试过这个,但是onCreateAnimation从未被调用。我正在使用来自支持包v4的Fragment,它没有onCreateAnimatior,只有onCreateAnimation。这两者有什么区别吗? - ffleandro
是的,FragmentManager fragmentManager = getActivity().getSupportFragmentManager(); FragmentTransaction ft = fragmentManager.beginTransaction(); ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right); ft.addToBackStack(null); ft.replace(R.id.tabContainer, fragment); ft.commit(); fragmentManager.executePendingTransactions(); - ffleandro
我也想实现相同的功能。我能在Fragment创建时获取事务动画,但是如何在事务完成/销毁时添加动画呢?有什么好方法吗? - CoDe
这个解决方案与使用setCustomAnimation不是非常兼容,正如@george所指出的那样(我假设你想调用super.onCreateAnimator并获取配置的动画)。它覆盖了它,但也在片段转换之外添加了配置更改的动画。在所有用例中都无法使用。 - Nilzor
我让它正常工作了,不再闪烁。我只是添加了这个: if (enter) super.onCreateAnimator(transit, enter, nextAnim); - pnavk
显示剩余5条评论

8

综合以上答案,以下是我使用支持库片段成功的示例。

只需扩展MenuFragment并设置侦听器以获取后续执行的回调。

public class MenuFragment extends Fragment {

private WeakReference<OnMenuClosedListener> onMenuClosedListener;

@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
    Animation anim = null;
    if (enter) {
        anim = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_slide_in_top);
    } else {
        anim = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_menu_slide_out_top);
        anim.setAnimationListener(new AnimationListener() {
            @Override public void onAnimationStart(Animation animation) {
            }
            @Override public void onAnimationRepeat(Animation animation) {
            }
            @Override public void onAnimationEnd(Animation animation) {
                onMenuClosed();
            }
        });
    }

    // NOTE: the animation must be added to an animation set in order for the listener
    // to work on the exit animation
    AnimationSet animSet = new AnimationSet(true);
    animSet.addAnimation(anim);

    return animSet;
}

private void onMenuClosed() {
    if (this.onMenuClosedListener != null) {
        OnMenuClosedListener listener = this.onMenuClosedListener.get();
        if (listener != null) {
            listener.onMenuClosed();
        }
    }
}

public void setOnMenuClosedListener(OnMenuClosedListener listener) {
    this.onMenuClosedListener = new WeakReference<MenuFragment.OnMenuClosedListener>(listener);
}

/**
 * Callback for when the menu is closed.
 */
public static interface OnMenuClosedListener {

    public abstract void onMenuClosed();

}

}


我尝试将动画添加到“AnimationSet”中,但是在退出时没有任何onAnimation回调被调用。 - Etienne Lawlor
对我有用,只需添加AnimationSet。 - Santacrab

2

从API 26版本开始(同时也包括Support库),您可以使用

 FragmentTransaction runOnCommit (Runnable runnable);

例如:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_from_left);
ft.show(YourFragment);
ft.commit();
ft.runOnCommit(() -> Your_Action_Here);

2
我尚未测试过这个功能,但是查看文档后发现,这个可运行函数会在事务提交时启动,而不是在动画完成后。即使它能正常工作,它只能在事务未添加到返回堆栈时使用,这是一个相当大的限制。 - chips
@Giuseppe 这将在事务提交后立即执行。你的答案不正确! - AouledIssa

1

我需要在Xamarin中完成这个任务。我的情况是当片段动画结束时,我需要一个回调函数。以下是我如何在没有任何闪烁的情况下使其工作(这是C# / Xamarin):

    public override Animation OnCreateAnimation(int transit, bool enter, int nextAnim)
    {
        Animation anim = base.OnCreateAnimation(transit, enter, nextAnim);

        if (anim == null && nextAnim != 0) {
            anim = AnimationUtils.LoadAnimation(Activity, nextAnim);
        }

        anim.SetAnimationListener(this);
        return anim;
    }

    public void OnAnimationEnd(Animation animation)
    {
    }

    public void OnAnimationRepeat(Animation animation)
    {
    }

    public void OnAnimationStart(Animation animation)
    {
    }

注意:
  • 父片段必须实现 Animation.IAnimationListener 接口
  • 你必须返回一个 AnimationSet,否则 FragmentManager 将覆盖你的监听器并且回调函数不会被触发。

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