Android Honeycomb:如何更改FrameLayout中的碎片,而无需重新创建它们?

时间:2011-05-31 09:03:36

标签: android android-3.0-honeycomb android-fragments

是否可以在片段之间切换而无需一直重新创建片段?如果是这样,怎么样?

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();

如果我调出设置,然后是别的,然后回到设置,吐司首先给我“null”,然后“设置:SettingsFragment {40ef ......”秒。

但是,如果我用fragmentTransaction.add(R.id.framelayout_content, set, SET);替换fragmentTransaction.replace(R.id.framelayout_content, set, SET);,我会一直得到“null”,“null”,“null”......所以它似乎没有找到Fragment by tag。 / p>

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大致相同。有没有一种简单的方法来防止这种情况?否则我想我可能会切换回隐藏/显示位。

4 个答案:

答案 0 :(得分: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(...),确保不添加到后面的堆栈。

答案 1 :(得分:4)

避免

  

IllegalStateException:Fragment   已添加

我找到了一个适合我的解决方法:在您的交易中使用remove(AFrag)add(BFrag),而不是replace()

看起来它是一个错误:4th comment in the accepted answer

答案 2 :(得分:1)

fragmentTransactionOnClick.setTransition(FragmentTransaction.TRANSIT_EXIT_MASK);

如果您添加。setTransition.exit transit_exit_mask,则之前的观看次数不会

答案 3 :(得分:0)

我找到了一种使用“标签”功能的方法:

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

//...

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

但是,这似乎有点异步。在findFragmentByTag返回commit之后直接拨打null。仅在后来,在OnOptionsItemSelected事件的情况下,才发现碎片。

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

我没有快速一瞥找到从我的FrameLayout获取“活动”片段的方法,所以我想我要在某处保存最后显示的Fragment的标签。