FragmentTransaction.replace()淡入过渡显示"ghost"片段

Roc*_*Lee 16 android android-animation android-fragments android-transitions

您可以下载我的整个项目来尝试和调试.这是我的整个代码的回购:https://bitbucket.org/lexic92/studio48/


当我尝试用空白片段替换空白片段时,我在转换中出现了"鬼片段".

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

导航抽屉:

  • 按钮1 - 带文本的片段
  • 按钮2 - 空的片段

    1. 当我打开应用程序时,它会从包含文本的片段开始.然后,我打开导航抽屉并单击按钮2. 转换不良,瞬间变为空白屏幕,然后切换回淡入淡出的文本,直到它变为空白屏幕.

    2. 如果我打开导航抽屉并再次单击按钮2 ,它将从全文淡出到空白屏幕.因此,对于一个瞬间,它会在不应该的情况下显示带有文本的片段.我一步一步地在调试模式下运行我的应用程序,以减慢速度,并验证这种行为确实发生了.

    3. 如果我第三次打开导航抽屉并再次单击按钮2 ,它正确地不会显示任何动画,因为它正在淡入同一个屏幕.

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

这是我的整个代码的回购: 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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

当我注释掉".setTransition"的2行并取消注释说".setCustomAnimations"的2行时,会发生同样的问题.以下是自定义动画:

RES /动画/ 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>
Run Code Online (Sandbox Code Playgroud)

RES /动画/ 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>
Run Code Online (Sandbox Code Playgroud)

如何在没有出现"ghost"片段的情况下顺利过渡?

规格:我在Google Nexus 5物理设备(不是模拟器)上运行android.support.v7.app.ActionBarActivity,minSdkVersion == 15和targetSdkVersion == 21.

我猜对答案:

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

就个人而言,这是碎片动画的zPosition的一个错误.

你看到的是新片段"出现",这是因为新片段附加在当前片段下面.

因此,当试图为现有片段的"Over the top"片段设置动画时,似乎没有任何事情发生,那么新的片段就会"出现".

我尝试了很多工作,玩zPosition(只影响windows而不是布局,所以对片段没有影响),onAnimationCreate()将根布局带到前面甚至动画开始和停止......似乎什么都不做.

所以在这个时间点没有为片段转换编写完整的自定义动画,它们现在有点儿麻烦.

你可能要玩..add(Fragment)等待它被添加,然后调用.remove(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();
            }
Run Code Online (Sandbox Code Playgroud)

正如引文所暗示的那样,在淡入新片段之前,当前片段可能会逐渐淡出这个"底层"片段吗?

我最终做了什么

注意:我不是把它作为答案,因为它在技术上没有回答我的问题,但它是我能提出的最好的备份计划解决方案.

我试过看看没有动画时问题是否解决了."幽灵片段"没有出现,但我确实注意到它花了一瞬间加载片段,看起来很刺耳和丑陋.我想要一个如丝滑的应用程序,如果在没有动画的情况下它不顺畅,那么即使我确实修复了鬼片段bug 也可能没有希望.我了解到碎片只是马车(见这里).

我决定隐藏并显示视图.这是我的新代码:

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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

我还将2个片段(空片段和带有大量文本的片段)的布局复制并粘贴到相同的布局中,作为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>
Run Code Online (Sandbox Code Playgroud)

它工作正常,但我只是不知道如何让它淡入淡出.但这是一个单独的堆栈溢出问题的问题.如果有人解决鬼片神秘,我很有兴趣知道答案.但是我决定我现在不会浪费时间试图解决这个问题,特别是当片段的过渡在过去被证明是错误的时候(就像那篇文章中那样).

Ell*_*ltz 0

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

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();
Run Code Online (Sandbox Code Playgroud)

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