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

相關問題