配置更改后片段丢失过渡动画

Posted

技术标签:

【中文标题】配置更改后片段丢失过渡动画【英文标题】:Fragment lost transition animation after configuration change 【发布时间】:2012-02-08 21:06:29 【问题描述】:

我正在使用以下代码将片段插入到活动中:

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);
    

当我在启动后通过返回按钮从后台弹出片段时,一切都很好,我可以看到淡出动画。但是,如果我旋转设备并按下后退按钮,那么片段就会消失而没有动画。

这是 Android 行为还是我做错了什么?

编辑: 旋转后 FragmentManager 似乎没有恢复 BackStackEntry 的动画(enterAnim、exitAnim、popEnterAnim 和 popExitAnim)。

FragmentManager 转储(无旋转):

Active Fragments in 4087d668:
  #0: SimpleFragment408883b0 #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=FragmentManager4087d668 in ListViewFragmentsActivity4087d588
    mImmediateActivity=my.app.ListViewFragmentsActivity@4087d588
    mActivity=my.app.ListViewFragmentsActivity@4087d588
    mNextAnim=17498112
    mContainer=android.widget.RelativeLayout@408876d8
    mView=android.widget.FrameLayout@40888a70
Added Fragments:
  #0: SimpleFragment408883b0 #0 id=0x7f050000 simple
Back Stack:
  #0: android.app.BackStackRecord@408884b8
    mName=simple mIndex=0 mCommitted=true
    mEnterAnim=#10b0000 mExitAnim=#10b0001
    Operations:
      Op #0:
        cmd=1 fragment=SimpleFragment408883b0 #0 id=0x7f050000 simple
    enterAnim=17498112 exitAnim=17498113
    popEnterAnim=17498112 popExitAnim=17498113
Back Stack Indices:
  #0: android.app.BackStackRecord@408884b8
FragmentManager misc state:
  mCurState=5 mStateSaved=false mDestroyed=false

FragmentManager 转储(旋转后):

Active Fragments in 40877f38:
  #0: SimpleFragment40878858 #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=FragmentManager40877f38 in ListViewFragmentsActivity40877e58
    mImmediateActivity=my.app.ListViewFragmentsActivity@40877e58
    mActivity=my.app.ListViewFragmentsActivity@40877e58
    mContainer=android.widget.RelativeLayout@4087ed50
    mView=android.widget.FrameLayout@4087fc00
Added Fragments:
  #0: SimpleFragment40878858 #0 id=0x7f050000 simple
Back Stack:
  #0: android.app.BackStackRecord@40878a78
    mName=simple mIndex=0 mCommitted=false
    Operations:
      Op #0:
        cmd=1 fragment=SimpleFragment40878858 #0 id=0x7f050000 simple
Back Stack Indices:
  #0: android.app.BackStackRecord@40878a78
FragmentManager misc state:
  mCurState=5 mStateSaved=false mDestroyed=false

【问题讨论】:

我也遇到了同样的问题。你有没有运气弄明白? @khendricks 不,你呢? 很遗憾没有。我很震惊,没有很多其他人抱怨这一点。我为此问题创建了一个错误报告。 code.google.com/p/android/issues/… @khendricks,试试 Android api 提供的 Support4Demos 示例项目。在运行时你可以观察/检查 Fragment->Custom Animation,在代码中观察文件 FragmentCustomAnimationSupport.java。即使您更改方向应用程序也不会崩溃,甚至动画也可以正常工作。请让我知道它是否适合你。 @khendricks 不,它显示了他所描述的确切行为。当你前进时它工作正常,但是当方向改变后返回时它不显示动画。它对我来说从来不是问题的原因是我们总是将方向设置为纵向或横向。 【参考方案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);
    

使用动画来支持库片段的技术相同。在这种情况下,您还可以根据片段状态和/或参数更好地控制播放动画的方式。

【讨论】:

使用 support-v4 时,您可以使用 onCreateAnimation()AnimationUtils 辅助类来加载动画。 请记住,这种机制无法处理使用不同的动画来弹出返回堆栈。您必须自己处理此流程。 这个方法会不会干扰transaction.setCustomAnimations?它可以设置动画两次。【参考方案2】:

好的,这是一个错误,也是本机库(不仅是支持库)的问题。

我可以建议的唯一解决方法是创建您自己的返回堆栈,然后在您返回自己的堆栈时使用您自己的自定义实现设置正确的动画来处理 onBack。

【讨论】:

【参考方案3】:

解决此问题的另一个建议是下载支持库的源代码并自己进行我在缺陷 (http://code.google.com/p/android/issues/detail?id=25994) 中建议的更改,当然这意味着您自己维护支持库的副本,而不是能否使用本机支持,但这取决于这个问题对您的重要性。

【讨论】:

【参考方案4】:

您可以对每个片段使用 onCreateAnimation 和 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);
    

【讨论】:

但是我们如何实现从右到右的动画呢?我的意思是,在进行片段事务时,您会传递 4 个不同的动画。 2 用于向前移动,2 用于 popbackstack。比如从右进入/从左退出,从左进入/从右退出【参考方案5】:

几天前在新的支持库23.3.0 中修复了这个错误。 https://code.google.com/p/android/issues/detail?id=25994#c36

【讨论】:

以上是关于配置更改后片段丢失过渡动画的主要内容,如果未能解决你的问题,请参考以下文章

片段中的某些视图未使用过渡动画

java 将循环显示和不显示过渡动画添加到Android片段

如何更改presentViewController过渡动画

如何在 SwiftUI 中动画/过渡文本值更改

我可以更改 Android startActivity() 过渡动画吗?

Plotly:如何更改动画热图中的过渡时间?