setRetainInstance(true)+ setCustomAnimations(…)=每个方向更改的animation?

背景

我有一个片段的活动,需要被创build时animation,但不是当方向改变时。

片段被dynamic地插入到布局中,因为它是导航 – 抽屉式活动的一部分。

问题

我想避免重新创buildconfiguration更改的片段,所以我在片段中使用了setRetainInstance。 它工作,但由于某种原因,animation也会重新启动,每次我旋转设备。

我做了什么

我已经添加到片段:

@Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); } 

这对于活动:

  final FragmentManager fragmentManager = getSupportFragmentManager(); final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); MyFragment fragment= (MyFragment) fragmentManager.findFragmentByTag(MyFragment.TAG); if (fragment== null) { fragmentTransaction.setCustomAnimations(R.anim.slide_in_from_left, R.anim.slide_out_to_right); fragment= new MyFragment(); fragmentTransaction .add(R.id.fragmentContainer, fragment, MyFragment.TAG).commit(); } 

fragment_container.xml

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/fragmentContainer" android:layout_width="match_parent" android:layout_height="match_parent" /> 

我试过了

  • 我试图通过使用“replace”而不是“添加”来解决它。 它没有帮助。
  • 我也试图总是执行片段的replace,如果片段已经存在,那么不要animation(在同一片段上)。
  • 如果我删除setRetainInstance调用,它的作品,但我想避免重新创build片段。

  1. 我该如何解决这个问题?
  2. 为什么我仍然得到添加片段的animation?
  3. 其他configuration更改时会发生什么?

解决方法#1

这个解决scheme通常会起作用,但是它会导致您尝试实现的生命周期中的糟糕事情:

  MyFragment fragment= (MyFragment) fragmentManager.findFragmentByTag(MyFragment.TAG); if (MyFragment== null) { MyFragment= new MyFragment(); fragmentManager.beginTransaction().setCustomAnimations(R.anim.slide_in_from_left, R.anim.slide_out_to_right) .replace(R.id.fragmentContainer, fragment, MyFragment.TAG).commit(); } else { //workaround: fragment already exists, so avoid re-animating it by quickly removing and re-adding it: fragmentManager.beginTransaction().remove(fragment).commit(); final Fragment finalFragment = fragment; new Handler().post(new Runnable() { @Override public void run() { fragmentManager.beginTransaction().replace(R.id.fragmentContainer, fragment, finalFragment .TAG).commit(); } }); } 

我仍然想看看可以做些什么,因为这可能会导致你不希望发生的事情(例如在onDetach中)。

解决方法#2

解决这个问题的一个方法就是避免通过fragmentManager添加animation,只是在片段生命周期内为视图本身做。 这是它的样子:

BaseFragment

 @Override public void onViewCreated(final View rootView, final Bundle savedInstanceState) { super.onViewCreated(rootView, savedInstanceState); if (savedInstanceState == null) rootView.startAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.slide_in_from_left)); } @Override public void onDestroyView() { super.onDestroyView(); if (!getActivity().isChangingConfigurations()) getView().startAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.fade_out)); } 

Solutions Collecting From Web of "setRetainInstance(true)+ setCustomAnimations(…)=每个方向更改的animation?"

你如何重写onCreateAnimation()方法,并防止在旋转后重新创build片段时发生animation?

如下所示: 如何在屏幕旋转后禁用/避免片段自定义animation


编辑:这是一个示例代码:

BaseFragment.java

 ... private boolean mNeedToAvoidAnimation; @Override public void onDestroyView() { super.onDestroyView(); mNeedToAvoidAnimation = true; } @Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { // This avoids the transaction animation when the orienatation changes boolean needToAvoidAnimation = mNeedToAvoidAnimation; mNeedToAvoidAnimation = false; return needToAvoidAnimation ? new Animation() { } : super.onCreateAnimation(transit, enter, nextAnim); } 

这个片段应该是这个活动中所有片段都会扩展的基础片段。

再看看你的代码:

 final FragmentManager fragmentManager = getSupportFragmentManager(); final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); MyFragment fragment= (MyFragment) fragmentManager .findFragmentByTag(MyFragment.TAG); if (fragment== null) { fragmentTransaction.setCustomAnimations(R.anim.slide_in_from_left, R.anim.slide_out_to_right); fragment= new MyFragment(); fragmentTransaction .add(R.id.fragmentContainer, fragment, PhoneInsertionFragment.TAG).commit(); } 

您正在使用MyFragment.TAG来查找片段,但是您正在使用MyFragment.TAG添加到事务中。

这就是为什么你每次都要重新创buildanimation和片段。 只需使用相同的标签来findadd ,它应该没问题。

为什么发生这种情况是因为当片段pipe理器试图在定向上重新附加片段时,它会应用已存储在事务中的animation。 (即你添加片段时设置的)。

我们通过处理活动本身的方向变化来解决这个问题 如果要更改UIdevise,请在onConfigChanges方法中附加和分离片段。