Android Fragment - 从一个视图移动到另一个视图?

Posted

技术标签:

【中文标题】Android Fragment - 从一个视图移动到另一个视图?【英文标题】:Android Fragment - move from one View to another? 【发布时间】:2013-03-27 10:26:31 【问题描述】:

我可以先将片段添加到视图,然后“分离”它,然后“重新附加”到另一个视图吗?

在代码中,我想:

fragOne one = new fragOne();
getSupportFragmentManager().beginTransaction()
        .add(R.id.left, one, "tag").commit();

getSupportFragmentManager().beginTransaction()
        .detach(one).commit();      // or .remove(), or .addToBackStack(null).remove()

getSupportFragmentManager().executePendingTransactions();

getSupportFragmentManager().beginTransaction()
        .add(R.id.right, one).commit();

但它会抛出错误:

04-05 13:28:03.492: E/androidRuntime(7195): java.lang.RuntimeException: Unable to start activity ComponentInfocom.example.trybackstack/com.example.trybackstack.MainActivity: java.lang.IllegalStateException: Can't change container ID of fragment fragOne40523130 #0 id=0x7f080000 tag: was 2131230720 now 2131230721

感谢您的帮助!

【问题讨论】:

您正面临此异常,因为您使用两个不同的 id 用于片段容器(即 R.id.right 和 R.id.left)来添加“片段一”。使用一个 id容器.. 确实如此。但我想将该片段从左向右移动。 在这种情况下,您需要先提交上一个事务,然后再次开始一个新事务以将相同的片段添加到不同的视图 我想我做到了,正如你所说的那样。最后一行是导致该异常的行。这是一笔新交易。 我刚刚尝试了一个新的解决方案。我认为它会起作用..来聊天 【参考方案1】:

我遇到了同样的问题,但我发现我真正需要的是重新设置片段的视图而不是片段本身,从而避免任何片段管理器事务。

View vv = fragment.getView();
ViewGroup parent = (ViewGroup)vv.getParent();
parent.removeView(vv);
newparent.addView(vv, layoutParams);

【讨论】:

这是最好的解决方案,因为视图层次结构不会被破坏和重新创建 是的,我完全同意,因为容器在大多数场景中都是一个简单的 FrameLayout,这种方法避免了使用 FragmentManager 和 Fragment 生命周期。 这对我不起作用,因为我想在方向改变时将片段从一个父级移动到另一个父级。所以在方向改变后,片段的宿主视图被破坏了。 老兄,你摇滚。像魅力一样工作。将此响应与medium.com/cs-random-thoughts-on-tech/… 结合起来,现在我有了一个 webview,可以在应用程序的任何地方传送而不会丢失状态...谢谢!!【参考方案2】:

在尝试了类似问题的所有答案后,看来我找到了解决问题的方法。

第一个问题 - 在尝试将片段添加到另一个容器之前,您确实必须提交执行删除事务。感谢nave's answer

但这并不是每次都有效。第二个问题是回栈。它以某种方式阻止了交易。

所以对我有用的完整代码如下所示:

manager.popBackStackImmediate(null, manager.POP_BACK_STACK_INCLUSIVE);
manager.beginTransaction().remove(detailFragment).commit();
manager.executePendingTransactions();
manager.beginTransaction()
    .replace(R.id.content, masterFragment, masterTag)
    .add(R.id.detail, detailFragment, activeTag)
    .commit();              

【讨论】:

这会导致视图被销毁并重新创建,而不是保留 在某些情况下这不起作用。我在 nave 的原始答案中得到了更好的结果:删除片段,杀死后台堆栈,然后添加片段。【参考方案3】:

我想你现在应该已经知道了,但我没有看到任何令人满意的答案。 因此,我将其发布给其他可能在未来参考此内容的人。

如果要将片段从一个视图移动到另一个视图,请执行以下操作:

android.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(fragment1);
fragmentTransaction.commit();
fragmentManager.executePendingTransactions();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.containerToMoveTo, fragment1);
fragmentTransaction.commit();

这样您就不必复制片段。

【讨论】:

它不起作用... 错误:java.lang.RuntimeException:无法启动活动 ComponentInfo:java.lang.IllegalStateException:无法更改片段 SubMenuFragment419b9c60 #1 id 的容器 ID =0x7f050036:以前是 2131034166 现在是 2131034167 实际上确实有效。在 Nexus7/2012/4.4 和 Galaxy SII/4.1.2 上测试。我究竟做错了什么? =) 看起来只有当你有一个空的后台堆栈时这才有效。这是改进的代码:***.com/a/21328919/1855764 这会导致视图被销毁并重新创建,而不是保留 - Greg Ennis 41 秒前编辑【参考方案4】:

请查看解决方案,如果要保存旧片段的状态,则需要创建同一个片段的新实例并使用旧片段的状态实例化它。

 FragmentTransaction ft = mFragmentManager.beginTransaction();
    ft.remove(one);
    Fragment newInstance = fetchOldState(one);
    ft.add(R.id.right, newInstance);
    ft.commit();


//TO fetch the old state
    private Fragment fetchOldState(Fragment f)
        
            try 
                Fragment.SavedState oldState= mFragmentManager.saveFragmentInstanceState(f);

                Fragment newInstance = f.getClass().newInstance();
                newInstance.setInitialSavedState(oldState);

                return newInstance;
            
            catch (Exception e) // InstantiationException, IllegalAccessException
            

            
        

【讨论】:

感谢您的回复@Karan_Rana!你的方法有效。但它实际上是复制片段,而不是真正移动它。我也发现一些人对此感到担忧。我不知道。但似乎对于一个 Fragment,一旦添加,我们就无法“重新添加”它。复制它似乎是迄今为止我发现的最好的方法。然而它可能会导致一个潜在的问题:它的引用可能不再起作用。【参考方案5】:

我也遇到过这个问题。有时移动片段有效,有时您必须创建一个新实例。如果片段一直处于“isRemoving”状态,移动片段似乎不起作用。 在 backstack 中有一个片段似乎也可以防止被删除。

【讨论】:

【参考方案6】:

添加到Yan. Yurkin's answer。确保不要对事务应用任何转换,因为这些似乎会延迟片段的分离。

【讨论】:

以上是关于Android Fragment - 从一个视图移动到另一个视图?的主要内容,如果未能解决你的问题,请参考以下文章

android 从viewpager中删除一个fragment的方法?怎么解决 在线等

Android - 如何从 FragmentActivity 访问 Fragment

Android Fragment,视图未删除

Android安卓viewpager和Fragment的结合,多个Fragment视图之间切换等运用

Android--Fragment基本介绍

Android Fragment 基本介绍