Подтвердить что ты не робот

После изменения конфигурации фрагмент потерял переходную анимацию

Я вставляю фрагменты в Activity с помощью этого кода:

public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    FragmentManager fm = getFragmentManager();
    String tag = "simple";

    Fragment fr = fm.findFragmentByTag(tag);
    if (fr == null)
    {
        SimpleFragment simpleFragment = new SimpleFragment(); 
        FragmentTransaction transaction = fm.beginTransaction();
        transaction.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out,
                                        android.R.animator.fade_in, android.R.animator.fade_out);
        transaction.add(R.id.main_layout, simpleFragment, tag);
        transaction.addToBackStack(tag);
        transaction.commit();
    }
}

Код фрагментов:

public class SimpleFragment extends ListFragment 
{
    @Override
    public void onActivityCreated(Bundle savedInstanceState) 
    {
        super.onActivityCreated(savedInstanceState);
        getView().setBackgroundColor(Color.YELLOW);
    }
}

Когда я вывожу фрагмент из backstack через кнопку "Назад" сразу после запуска, тогда все в порядке, и я вижу, как исчезает анимация. Но если я вращаю устройство и нажимаю кнопку "Назад", фрагмент исчезает без анимации.

Является ли это поведение Android или я что-то не так?

EDIT: Кажется, что после ротации FragmentManager не восстанавливал анимацию (enterAnim, exitAnim, popEnterAnim и popExitAnim) для BackStackEntry.

Сброс FragmentManager (без вращения):

Active Fragments in 4087d668:
  #0: SimpleFragment{408883b0 #0 id=0x7f050000 simple}
    mFragmentId=#7f050000 mContainerId#=7f050000 mTag=simple
    mState=4 mIndex=0 mWho=android:fragment:0 mBackStackNesting=1
    mAdded=true mRemoving=false mResumed=true mFromLayout=false mInLayout=false
    mHidden=false mDetached=false mRetainInstance=false mRetaining=false mHasMenu=false
    mFragmentManager=FragmentManager{4087d668 in ListViewFragmentsActivity{4087d588}}
    [email protected]
    [email protected]
    mNextAnim=17498112
    [email protected]
    [email protected]
Added Fragments:
  #0: SimpleFragment{408883b0 #0 id=0x7f050000 simple}
Back Stack:
  #0: [email protected]
    mName=simple mIndex=0 mCommitted=true
    mEnterAnim=#10b0000 mExitAnim=#10b0001
    Operations:
      Op #0:
        cmd=1 fragment=SimpleFragment{408883b0 #0 id=0x7f050000 simple}
    enterAnim=17498112 exitAnim=17498113
    popEnterAnim=17498112 popExitAnim=17498113
Back Stack Indices:
  #0: [email protected]
FragmentManager misc state:
  mCurState=5 mStateSaved=false mDestroyed=false

Сброс FragmentManager (после вращения):

Active Fragments in 40877f38:
  #0: SimpleFragment{40878858 #0 id=0x7f050000 simple}
    mFragmentId=#7f050000 mContainerId#=7f050000 mTag=simple
    mState=4 mIndex=0 mWho=android:fragment:0 mBackStackNesting=1
    mAdded=true mRemoving=false mResumed=true mFromLayout=false mInLayout=false
    mHidden=false mDetached=false mRetainInstance=false mRetaining=false mHasMenu=false
    mFragmentManager=FragmentManager{40877f38 in ListViewFragmentsActivity{40877e58}}
    [email protected]
    [email protected]
    [email protected]
    [email protected]
Added Fragments:
  #0: SimpleFragment{40878858 #0 id=0x7f050000 simple}
Back Stack:
  #0: [email protected]
    mName=simple mIndex=0 mCommitted=false
    Operations:
      Op #0:
        cmd=1 fragment=SimpleFragment{40878858 #0 id=0x7f050000 simple}
Back Stack Indices:
  #0: [email protected]
FragmentManager misc state:
  mCurState=5 mStateSaved=false mDestroyed=false
4b9b3361

Ответ 1

В качестве обходного пути для этого вы можете использовать методы onCreateAnimator/onCreateAnimation в своих фрагментах.

Например, для реализации собственных фрагментов:

@Override
public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
    if (enter) {
        return AnimatorInflater.loadAnimator(getActivity(), R.animator.slide_in_top);
    } else {
        return AnimatorInflater.loadAnimator(getActivity(), R.animator.fade_out);
    }
}

Такая же методика для фрагментов библиотеки поддержки с анимацией. В этом случае вы также имеете больший контроль над тем, как вы хотите играть в анимацию в зависимости от состояния фрагмента и/или аргументов.

Ответ 2

Хорошо, так что это ошибка, которая также является проблемой для родной библиотеки (а не только для библиотеки поддержки).

Единственное обходное решение, которое я могу предложить, - создать свой собственный задний стек, а затем обработать onBack с вашей собственной настраиваемой реализацией, настроив правильную анимацию, когда вы вернетесь через свой собственный стек.

Ответ 3

Альтернативное предложение по решению этой проблемы - загрузить источник для библиотеки поддержки и внести изменения, которые я предложил в дефект (http://code.google.com/p/android/issues/detail?id=25994), конечно, это означает, что вы сами поддерживаете копию библиотеки поддержки и не можете использовать встроенную поддержку, но это зависит от того, насколько важна эта проблема для вас.

Ответ 4

Вы можете использовать onCreateAnimation plus AnimationUtils для каждого фрагмента вместо transaction.setCustomAnimations(..). Также, чтобы пропустить анимацию во время восстановления, подумайте о более голубом флаге.

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    mIsRestoring = savedInstanceState != null;
    ...
}

@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
    if (mIsRestoring) {
        mIsRestoring = false;
        return null;
    }
    if (enter) {
        return AnimationUtils.loadAnimation(getContext(), R.anim.enter_from_right);
    } else {
        return AnimationUtils.loadAnimation(getContext(), R.anim.exit_to_left);
    }
}