9

我可以先向视图中添加一个片段,然后“分离”它,然后“重新附加”到另一个视图?Android片段 - 从一个视图移动到另一个视图?

在代码中,我想:

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 ComponentInfo{com.example.trybackstack/com.example.trybackstack.MainActivity}: java.lang.IllegalStateException: Can't change container ID of fragment fragOne{40523130 #0 id=0x7f080000 tag}: was 2131230720 now 2131230721 

感谢您的帮助!

+0

由于你使用的是两个不同的ID,用于片段容器(即R.id.right和R.id.left),用于将“片段一”。用一个单一的ID为容器面对此异常。 – 2013-04-05 05:45:19

+1

确实。但我想从左到右移动该片段。 – midnite 2013-04-05 05:53:00

+0

在这种情况下,您需要首先提交上一个事务,然后再次开始一个新事务,以将相同的片段添加到不同的视图 – 2013-04-05 05:57:56

回答

2

请检查解决方案,如果要保存旧片段的状态,则需要创建同一片段的新实例并将其与旧片段的状态实例化。

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 
      { 

      } 
     } 
+1

感谢您的回复@Karan_Rana!你的方法有效。但它实际上是_duplicating_片段,但不是真的移动它。我也发现了一些关于这方面的人。我不确定。但是对于片段来说,一旦添加它,我们就不能“重新添加”它。重复它似乎是迄今为止我发现的最好的方法。但它可能会导致一个潜在的问题:引用它可能不再有效。 – midnite 2013-04-06 23:34:13

+0

欢迎@midnite – 2013-04-08 03:22:16

8

我想你现在已经想通了,但我没有看到任何满意的答案。 所以,我将这个帖子发布给其他将来可能会参考的人。

如果你想从一个视图移动片段到另一个你做到以下几点:

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

这样你就不必重复片段。

+1

它不起作用... 错误:java.lang.RuntimeException:无法启动活动ComponentInfo:java.lang.IllegalStateException:无法更改片段的容器ID SubMenuFragment {419b9c60#1 id = 0x7f050036 }:现在是2131034166 2131034167 – Accollativo 2013-09-12 13:21:26

+1

其实这是行不通的。测试Nexus7/2012/4.4和Galaxy SII/4.1.2。我究竟做错了什么? =) – mjollneer 2013-12-04 08:46:20

+1

看起来像这样,只有当你有一个空的回栈时才有效。这是改进的代码:http://stackoverflow.com/a/21328919/1855764 – 2014-01-24 09:26:10

0

我也遇到过这个问题。有时移动片段有效,有时你必须创建一个新的实例。似乎移动片段不起作用,如果片段继续处于“isRemoving”状态。 被移除似乎也被阻止在后台堆栈中有一个碎片。

9

尝试从类似问题的所有答案后,看起来像我找到了一种方法来实现这个诀窍。

第一个问题 - 你真的要提交试图片段添加到另一个容器之前执行删除事务。感谢那去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();    
+2

这会导致视图被销毁并重新创建,而不是保存 – 2014-12-06 17:57:51

+0

在某些情况下,这是行不通的。我在nave的原始答案中得到了更好的结果:删除片段,杀死后台,然后添加片段。 – Theo 2014-12-13 19:01:46

0

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

11

我有同样的问题,但我发现我真正需要的是重建片段的视图,而不是片段本身,从而避免任何fragmentManager交易。

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

这是最好的解决方案,因为视图层次不会被破坏和重新创建。 – 2014-12-06 17:58:15

+1

是的,我完全同意,因为容器在大多数Senarios中都是一个简单的FrameLayout,并且这种方法避免了使用FragmentManager和Fragment生命周期进行播放。 – 2015-02-19 11:53:00

相关问题