2011-05-31 49 views
14

是否可以在碎片之间切换而不必一直重新创建碎片?如果是这样,怎么样?Android Honeycomb:如何更改FrameLayout中的碎片,而不重新创建它们?

In the documentation我找到了一个如何替换Fragments的例子。

// Create new fragment and transaction 
Fragment newFragment = new ExampleFragment(); 
FragmentTransaction transaction = getFragmentManager().beginTransaction(); 

// Replace whatever is in the fragment_container view with this fragment, 
// and add the transaction to the back stack 
transaction.replace(R.id.fragment_container, newFragment); 
transaction.addToBackStack(null); 

// Commit the transaction 
transaction.commit(); 

但我不想从头开始创建我的碎片,每当我需要它们时。

我也发现了隐藏的this example /显示片段:

// The content view embeds two fragments; now retrieve them and attach 
// their "hide" button. 
FragmentManager fm = getFragmentManager(); 
addShowHideListener(R.id.frag1hide, fm.findFragmentById(R.id.fragment1)); 
addShowHideListener(R.id.frag2hide, fm.findFragmentById(R.id.fragment2)); 

但我怎么会创建一个XML文件之外的ID的片段?

我认为这可能与this question有关,但是没有答案。 :/

非常感谢你提前, 水母

编辑:

这就是我正在做的现在:

Fragment shown = fragmentManager.findFragmentByTag(shownFragment); 

//... 

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 
if (shown != null) fragmentTransaction.hide(shown); 

//switch statetement for menu selection, just one example: 

SettingsFragment set = (SettingsFragment) fragmentManager.findFragmentByTag(SET); 
Toast.makeText(this, "Settings:" + set, Toast.LENGTH_LONG).show(); 
if (set == null) 
{ 
     set = new SettingsFragment(); 
     fragmentTransaction.add(R.id.framelayout_content, set, SET); 
} 
else fragmentTransaction.show(set); 
shownFragment = SET; 
fragmentTransaction.commit(); 

如果我调出设置,然后再回到设置,敬酒先给我“空”,然后“设置:SettingsFragment {40ef ...”秒。

但是,如果我将fragmentTransaction.add(R.id.framelayout_content, set, SET);替换为fragmentTransaction.replace(R.id.framelayout_content, set, SET);我总是收到“null”,“null”,“null”...所以它似乎没有找到Fragment by标记。

EDIT2:

添加fragmentTransaction.addToBackStack(null);的伎俩。 :) 这节省了整个隐藏/记忆哪个片段显示部分,所以我想这是最优雅的解决方案。

我发现this教程对这个话题很有帮助。

EDIT3:

看着我的代码,我意识到我可以摆脱一些地方,所以我把它改为:

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 
if (shown != null) fragmentTransaction.hide(shown); 
Settings set = (Settings) fragmentManager.findFragmentByTag(SET); 
if (set == null) set = new Settings(); 

fragmentTransaction.replace(R.id.framelayout_content, set, SET); 
fragmentTransaction.addToBackStack(null); 
fragmentTransaction.commit(); 

然而,这种调用的IllegalStateException: Fragment already added,很多同样喜欢here。有没有简单的方法来防止这种情况?否则,我想我可能会切换回隐藏/显示位。

回答

5

这可能取决于您试图避免重新创建的内容。

// Replace whatever is in the fragment_container view with this fragment, 
// and add the transaction to the back stack 
transaction.replace(R.id.fragment_container, newFragment); 
transaction.addToBackStack(null); 

在您的例子例如,当你打从你newFragment后退按钮前面的片段将显示(你会得到一个onCreateView,onActivityCreated但没有的onCreate),这样的片段不被作为重新创建这样。至于你newFragment,如果你打算再次使用它来更新任何内部状态,如onCreate或onActivityCreated所要求的,你仍然可以保留它。

编辑:

如果你只是有每个条目在右窗格中,然后添加到后退堆栈调用不同片段的菜单列表是不是你想要的。为此,您可能会在每个片段前面调用add(...),并根据需要简单地隐藏/显示每个片段(我没有测试过)。否则,我会建议持有每个片段的引用,请致电replace(...)选择不同的菜单项,以确保您不会添加到后端堆栈。

+0

我想根据菜单选择在碎片之间进行切换,所以如果你再次选择相同的菜单项,我想再次显示相同的碎片。通过标签找到片段 – jellyfish 2011-06-01 08:37:31

+1

然后,我会坚持片段在内存中,并进行替换。我不明白为什么你需要找到片段,因为你可以跟踪当前的菜单选择,并知道什么片段是然而,当选择一个新的菜单项时,我不明白为什么找到片段标签不应该工作(我已经做了类似于DialogFragment的内容,如果内存服务,API中的DialogFragment示例演示。 – PJL 2011-06-01 19:55:41

+0

那么,你是否建议我应该在我的课堂中为每个片段保留一个参考场?对于另一部分,请参阅我的编辑。 – jellyfish 2011-06-06 08:51:34

0

我发现使用“标签”功能的方法:

//... 
fragmentTransaction.add(R.id.framelayout_content, fragment1, "foo"); 
fragmentTransaction.add(R.id.framelayout_content, fragment2, "bar"); 

//... 

fragmentManager.findFragmentByTag("foo"); 
fragmentManager.findFragmentByTag("bar"); 

然而,这看似有点异步。在commit返回null之后直接调用findFragmentByTag。之后,在我的案例中,发现了一个OnOptionsItemSelected事件。

还有一个叫做findFragmentById(int)的功能,但它不是很有用。 Id - 如果没有在XML布局中指定 - 与容器相同,则在此情况下为R.id.framelayout_content。如果稍后使用此ID调用该函数,则只能访问其中一个附加碎片。 (我猜这是最后一个,但没有检查过,似乎总是一样的。)

我没有通过快速的一瞥找到一种方法来从我的“活动”片段FrameLayout,所以我想我会保存最后显示的Fragment的标签。

+1

“在调用后直接调用findFragmentByTag将返回null”可能是由于:调用commit()不会立即执行事务。相反,只要线程能够这样做,它就会安排它在活动的UI线程(“主”线程)上运行。“ [Android开发人员] http://developer.android.com/guide/components/ fragments.html#Transactions) – PKeno 2012-08-03 09:09:54

4

为了避免

IllegalStateException异常:片段 已经添加

我发现,工作正常,我一个解决方法:在你的事务中使用remove(AFrag)add(BFrag),而不是replace()

它看起来像一个bug:4th comment in the accepted answer

+0

PJL在他的评论中提到了类似的东西。所以删除/添加保持片段活着,其内容保存? – jellyfish 2011-06-08 14:47:31

+0

是的,在remove/add操作和popBackStack mAFrag保留其内容之后,我保留对mAFrag和mBFrag的引用。此外,如果我再次前进,mBFrag也会保留内容。我刚刚发现@PJL评论,它被隐藏了。对不起:S – 2011-06-09 08:20:23

+0

但remove()也会删除片段的父视图,而replace()不会 – 2011-11-27 07:58:10

1
fragmentTransactionOnClick.setTransition(FragmentTransaction.TRANSIT_EXIT_MASK); 

如果添加。 setTransition.exit transit_exit_mask那么以前的视图不会来

相关问题