将Android片段移动到另一个容器中 无法更改片段的容器ID

8

我希望我的应用程序在平板电脑上能够实现以下功能。片段(0)有一些菜单,将显示片段(1)…(n)的内容,如下所示:

-----------------
|   |   |   |   |
|   |   |   |   |
|(0)| X | X | X |
|   |   |   |   |
|   |   |   |   |
-----------------
 becomes
-----------------
|   |   |   |   |
|   |   |   |   |
|(0)|(1)| X | X |
|   |   |   |   |
|   |   |   |   |
-----------------
 and then
-----------------
|   |   |   |   |
|   |   |   |   |
|(0)|(2)|(1)| X |
|   |   |   |   |
|   |   |   |   |
-----------------
 etc... 

Fragment0不会移动,其他的片段都会向右移动。超出边缘的片段将被销毁。

因此,我使用了一个水平LinearLayout的XML布局,并包含4个带有正确ID(fragment0... fragment3)的FrameLayout。

我可以实例化并显示fragment0,然后是fragment1,但是我无法在此之后将其向右移动,我得到以下错误:

ERROR/AndroidRuntime(343): FATAL EXCEPTION: main
java.lang.IllegalStateException: Can't change container ID of fragment ...

我找到的唯一相关问题是这个那个,尝试了所有不同的解决方案但没有成功。
尝试使用FragmentTransaction.remove()后跟.add(),尝试使用.replace(),尝试以不同的顺序执行它们,并在中途提交(甚至尝试像某些人建议的那样提交两次),尝试调用addToBackStack()……仍然没有成功。
问题是是否可以使用FragmentTransaction这样移动片段。如果可以,我做错了什么(并且奖励是可以动画化的吗?)。如果不行,实现这个的正确方法是什么?
请注意,我不想每次重新实例化片段(每个都会在Web上进行一些查询,可能需要一些时间)。可以将所有数据提取回活动以重新创建一个,但如果可能的话,我宁愿不这样做……
2个回答

24

可以使用remove()函数更改片段的容器。

问题在于commit()。它是一个异步调用,并且会安排在主线程上执行。因此,为了强制FragmentManager在将其添加到其他容器之前立即执行它,我们需要使用executePendingTransactions()函数。在调用此函数后,请尝试将片段添加到新容器中。

文档:executePendingTransactions()

示例代码:

FragmentManager fManager = getSupportFragmentManager();
FragGroups fragGroups = (FragGroups) fManager.findFragmentByTag("groups");
if (fragGroups != null) {
     fManager.beginTransaction().remove(fragGroups).commit();
     fManager.executePendingTransactions();
} else {
     fragGroups = new FragGroups();
}
if (mTwoPane) {
    fManager.beginTransaction().replace(R.id.fragment_container_groups, fragGroups, "groups").commit();
} else {
    fManager.beginTransaction().replace(R.id.fragment_container, fragGroups, "groups").commit();
}

享受。欢迎反馈。

编辑

我想在这里补充一点。由于我遇到了同样的问题,找到了这个帖子并应用了建议的更改。问题仍然存在。然后我查看了此线程中的最后一条评论,解决了我的问题:在提交事务时删除addToBackStack()方法,或者如果您有意使用它,请在将其添加到另一个容器之前从返回堆栈中删除该片段。希望能帮助未来的读者。


1
非常好的答案!也许不完全符合原问题的要求,但我发现它非常有用。 - Tom R
2
Pavan......我甚至不认识你......你也不认识我......但是我对你有着深深的爱,我的朋友。 - dell116
@TomR,我很高兴你觉得它有用 :) - Pavan Jaju
好的,我也想这么做 :D - cesards
2
该解决方案的问题在于无法将第一笔交易添加到后退栈中。这样做会再次出现原始错误“无法更改容器ID”。 - Casey Perkins

3
我不确定这是否符合您的要求,但我为您的问题制作了一个小示例。基本上,您将使用布局文件进行正确的移位,为每个移位片段设置包装器容器。代码示例有点大,无法在答案中展示,因此我已将其发布到此处的Gist中。在该示例中,按下每个ListFragment的项目(片段1 ->片段2 ->片段3)以查看其行为。

它不能做我想要的事情,但我正在尝试改变你的代码让它能够做到...如果我成功了,我会发布出来的。 - Matthieu
我的意思是在@Matthieu的例子中,第33行LinearLayout main_linear = (LinearLayout) getActivity().findViewById(R.id.main_linear);对我来说很奇怪。 - midnite
@midnite 好的,你应该问他,那不是我的代码,我无法帮助你(那个ID也没有出现在布局文件中???)。 - user
是的,我正在使用LinearLayout,但我不认为这真的有什么关系。 - Matthieu
@Matthieu 这是一个旧问题,所以我不确定问题是什么,但我认为midnite指的是我们示例代码之间的差异(你的更加完善)。 - user
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接