FragmentTransaction.replace() 淡入过渡显示“幽灵”片段

Posted

技术标签:

【中文标题】FragmentTransaction.replace() 淡入过渡显示“幽灵”片段【英文标题】:FragmentTransaction.replace() fade-in transition shows "ghost" fragment 【发布时间】:2015-09-13 06:34:24 【问题描述】:

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


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

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

导航抽屉:

按钮 1 - 带有文本的片段

按钮 2 - 为空的片段

    当我打开应用程序时,它从带有文本的片段开始。然后,我打开导航抽屉并单击按钮 2。过渡效果不佳,瞬间变成空白屏幕,然后切换回淡入淡出的文本,直到变成空白屏幕。

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

    如果我打开导航抽屉并第三次单击按钮 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();
        
    

当我注释掉说“.setTransition”的 2 行并取消注释说“.setCustomAnimations”的 2 行时,也会出现同样的问题。以下是自定义动画:

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

就我个人而言,这是片段的 zPosition 的错误 动画。

您看到的是“出现”的新片段,这是因为新的 片段附加在当前片段下方。

因此,当尝试为现有片段的“上方”设置动画时 片段,似乎什么都没有发生,然后新的只是 '出现'。

我尝试了很多变通方法,使用 zPosition(仅影响 窗口不是布局,所以对片段没有影响),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();
            

也许当前片段正在淡出到这个“基础”片段,正如引用所暗示的那样,在淡入新片段之前?

我最终做了什么

注意:我没有将其作为答案,因为它在技术上无法回答我的问题,但这是我能想到的最佳备用计划解决方案。

我尝试查看当有 no 动画时问题是否已解决。 “幽灵片段”没有出现,但我确实注意到加载片段需要一瞬间,看起来很刺耳和丑陋。我想要一个丝般流畅的应用程序,如果没有没有动画时它不流畅,那么即使我确实修复了幽灵片段错误,它也可能是无望的。我了解到片段只是错误的(参见here)。

我决定改为隐藏和显示视图。这是我的新代码:

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

我还复制并粘贴了 2 个片段的布局(空白片段和包含大量文本的片段)到相同的布局中,作为 FrameLayout 父级的子级:

fragment_songlist_detail.xml:

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

它工作正常,但我只是不知道如何让它淡入淡出。但这是一个单独的堆栈溢出问题的问题。如果有人解开幽灵碎片之谜,我很想知道答案。但我决定我现在不打算浪费时间去弄清楚它,尤其是当片段的转换在过去被证明是错误的时候(比如article)。

【问题讨论】:

这不是您问题的解决方案,但您可以尝试“FragmentTransaction.TRANSIT_FRAGMENT_OPEN” @savepopulation 我刚试了一下,还是一样的问题,只是动画看起来不一样。 @RockLee 你还有这个问题吗? 您找到解决方案了吗?我有同样的问题.. 不,我没有。我很惊讶它在 3 年后仍然是一个问题 - 我希望 Android 能够修复它。 :\ 【参考方案1】:

对所有事务调用执行此操作

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

【讨论】:

以上是关于FragmentTransaction.replace() 淡入过渡显示“幽灵”片段的主要内容,如果未能解决你的问题,请参考以下文章