android - FragmentTransaction.replace()淡入过渡显示 “ghost” fragment

标签 android android-fragments android-animation android-transitions

您可以下载我的整个项目以进行尝试和调试。这是我整个代码的 repo :https://bitbucket.org/lexic92/studio48/

当我尝试用空白片段替换空白片段时,过渡中出现“幽灵片段”。

如何重现问题:
我有一个导航抽屉,当我单击一个项目时,它会打开一个片段,该片段会填满整个屏幕。

导航抽屉:

  • 按钮1-带有文本
  • 的片段
  • 按钮2-空的片段
  • 打开应用程序时,它以带有文本的片段开始。然后,我打开导航抽屉,然后单击按钮2。过渡效果很差,一瞬间变成了空白屏幕,然后切换回淡入淡出的文本,直到变成空白屏幕。
  • 如果我打开导航抽屉并再次单击按钮2,它将从全文淡入空白屏幕。因此,一秒钟,它在不应该显示的文本片段中显示该片段。 我逐步在 Debug模式下运行了我的应用程序,以使其变慢并验证此行为是否确实发生。
  • 如果我打开导航抽屉并再次第三次单击按钮2,则正确地不显示任何动画,因为它正在淡入同一屏幕。

  • 有谁知道为什么会这样吗?您认为这与导航抽屉有关系吗?

    这是我整个代码的 repo : https://bitbucket.org/lexic92/studio48/

    以下是一些代码摘录:

    SongDetailActivity.java:
          @Override
          public void onNavigationDrawerItemSelected(int position) {
            // update the main content by replacing fragments
            FragmentManager fragmentManager = getSupportFragmentManager();
    
            //OPEN THE BLANK SCREEN
            if(position == 1) {
                fragmentManager.beginTransaction()
                        //.setCustomAnimations(R.anim.fade_in, R.anim.fade_out)
                        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
                        .replace(R.id.songlist_detail_container, PlaceholderFragment.newInstance(position + 1, mSongId))
                        .commit();
            }
            //OPEN THE SCREEN WITH TEXT
            else {
                SongDetailFragment sdf = new SongDetailFragment();
                Bundle args = new Bundle();
                args.putString(SongDetailFragment.ARG_ITEM_ID, mSongId);
                sdf.setArguments(args);
                fragmentManager.beginTransaction()
                        //.setCustomAnimations(R.anim.fade_in, R.anim.fade_out)
                        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
                        .replace(R.id.songlist_detail_container, sdf)
                        .commit();
            }
        }
    

    当我注释掉表示“.setTransition”的两行并取消注释说“.setCustomAnimations”的两行时,会发生相同的问题。以下是自定义动画:

    res/anim/fade_out.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
               android:duration="@android:integer/config_mediumAnimTime" />
    </set>
    

    res/anim/fade_in.xml
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
               android:duration="@android:integer/config_mediumAnimTime" />
    </set>
    

    如何在不显示“鬼影”片段的情况下使其平稳过渡?

    规范:我在Google Nexus 5物理设备(而非仿真器)上使用android.support.v7.app.ActionBarActivity,minSdkVersion == 15和targetSdkVersion == 21运行。

    我对答案的猜测:

    这个网站似乎给了我一个提示:http://gotoanswer.com/?q=Android+Animation+within+a+Fragment+not+working

    Personally for me this is a bug with the zPosition for Fragment animations.

    What you see is the new fragment "appearing" this is because the new fragment is attached underneath the current one.

    So when trying to animate a fragment 'Over the top' of an existing fragment, it appears like nothing is happening then the new one just 'appears'.

    I have tried many work arounds, playing with zPosition (only affects windows not layouts, so no effect to fragments), onAnimationCreate() bringing the root layout to front or even on animation start and stop... seems to do nothing.

    So at this point in time without writing a complete custom animation for fragment transitions, they are a bit buggy at the moment.

    You may have to play with. .add(Fragment) wait for it to be added, then call .remove(Fragment) removing the old fragment, that way the new fragment is physically placed on top of the existing fragment.



    我确实注意到,即使没有单击导航抽屉,在SongDetailActivity.java实例化时也会调用此代码 :
    //OPEN THE SCREEN WITH TEXT
                else {
                    SongDetailFragment sdf = new SongDetailFragment();
                    Bundle args = new Bundle();
                    args.putString(SongDetailFragment.ARG_ITEM_ID, mSongId);
                    sdf.setArguments(args);
                    fragmentManager.beginTransaction()
                            //.setCustomAnimations(R.anim.fade_in, R.anim.fade_out)
                            .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
                            .replace(R.id.songlist_detail_container, sdf)
                            .commit();
                }
    

    如引用所示,当前片段可能正在淡入该“底层”片段,而淡出到新片段之前呢?

    我最终做了什么

    注意:我并不是要回答这个问题,因为它在技术上不能回答我的问题,但这是我能想到的最好的备份计划解决方案。

    我尝试查看没有动画时问题是否解决。 “幽灵碎片”没有出现,但是我确实注意到,花了片刻的时间来加载碎片,看起来有些刺耳和丑陋。我想要一个柔滑的应用程序,如果没有动画时它也不平滑,那么即使我确实修复了幽灵片段错误,也可能毫无希望。我了解到片段只是 buggy (请参阅here)。

    我决定隐藏并显示 View 。这是我的新代码:

    SongDetailActivity.java
    //---------- NAVIGATION DRAWER -------------
        @Override
        public void onNavigationDrawerItemSelected(int position) {
    
            //HOME
            if (position == 0) {
    
            }
            //LYRICS
            else if(position == 1) {
                findViewById(R.id.lyrics).setVisibility(View.VISIBLE);
                findViewById(R.id.info).setVisibility(View.INVISIBLE);
    
            }
            //INFO
            else if(position == 2) {
                findViewById(R.id.info).setVisibility(View.VISIBLE);
                findViewById(R.id.lyrics).setVisibility(View.INVISIBLE);
            }
        }
    

    我还复制并粘贴了两个片段的布局(空片段和一个带有大量文本的片段)到同一布局中,作为FrameLayout父级的子代:

    fragment_songlist_detail.xml:
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_height="match_parent"
        android:background="#f8bbd0"
        android:layout_width="match_parent"
        >
        <LinearLayout
            android:id="@+id/lyrics"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            xmlns:android="http://schemas.android.com/apk/res/android">
        ...
        </LinearLayout>
        <LinearLayout
            android:id="@+id/info"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            xmlns:android="http://schemas.android.com/apk/res/android">
        ...
        </LinearLayout>
    </FrameLayout>
    

    它工作正常,但我只是不知道如何使其淡入淡出。但这是一个单独的堆栈溢出问题。如果有人解决了幽灵碎片之谜,我很想知道答案。但是我认为我现在不会浪费时间试图弄清楚它,特别是当片段的过渡在过去被证明是 buggy 时(例如article)。

    最佳答案

    为您的所有交易调用执行此操作

    fragmentManager.beginTransaction().setTransition(FragmentTransaction.
                                TRANSIT_FRAGMENT_FADE).remove(current_fragment).commit();
    fragmentManager.beginTransaction().add(R.id.songlist_detail_container, PlaceholderFragment.
                               newInstance(position + 1, mSongId)).commit();
    

    看看是否有帮助。这个想法是先提交一个删除,再提交一个添加。你也可以去FragmentManager.hide(Fragment);

    关于android - FragmentTransaction.replace()淡入过渡显示 “ghost” fragment ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31070913/

    相关文章:

    android - 如何在不自动播放过渡的情况下恢复 MotionLayout 的过渡状态?

    android - 在 Jetpack Compose 中启动动画矢量 Drawable

    android - 如何在 Android 中选择一个文件并计算其哈希值 (SHA-256)

    java - 根据分辨率更改 3D 模型纹理

    java - 为什么我的应用程序会因为 ImageView 而崩溃?

    安卓。内存泄漏导致内存不足错误。使用查看寻呼机。

    android - 分享图片元素过渡显示不正确的尺寸

    android - 如何重用 ListView 的方法?

    android - 在 Linux 平台上运行 Android 应用程序

    android - Recyclerview 项目首次未显示