在单个活动中切换片段

11
我想创建一个Activity,其中显示用户可以浏览的菜单。通过点击项目,会显示一个新屏幕,允许用户获得更多选项(类似向导)。 我想使用Fragment来实现这个功能,但是目前它对我来说不起作用。 现在我有: main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:id="@+id/main_fragmentcontainer" >

    <fragment
        android:id="@+id/mainmenufragment"
        android:name="com.myapp.MainMenuFragment"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

    <fragment
        android:id="@+id/secondmenufragment"
        android:name="com.myapp.SecondMenuFragment"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

MainMenuFragment 与一个 OnClickListener

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.mainmenu, container, false);

    setupButton(view);
    return view;
}

/* Button setup code omitted */

@Override
public void onClick(View v) {
    SherlockFragment secondRunMenuFragment = (SherlockFragment) getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.secondmenufragment);
    FragmentTransaction transaction = getSherlockActivity().getSupportFragmentManager().beginTransaction();

    transaction.replace(android.R.id.content, secondMenuFragment); //also crashes with R.id.main_fragmentcontainer
    transaction.addToBackStack(null);
    transaction.commit();
}

现在当我按下按钮时,应用程序会崩溃并显示以下logcat日志:
06-27 01:45:26.309: E/AndroidRuntime(8747): java.lang.IllegalStateException: 无法更改片段SecondMenuFragment {405e2a70 #1 id = 0x7f060029}的容器ID:原为2131099689,现在为2131099687
06-27 01:45:26.309: E/AndroidRuntime(8747): at android.support.v4.app.BackStackRecord.doAddOp(Unknown Source)
06-27 01:45:26.309: E/AndroidRuntime(8747): at android.support.v4.app.BackStackRecord.replace(Unknown Source)
06-27 01:45:26.309: E/AndroidRuntime(8747): at android.support.v4.app.BackStackRecord.replace(Unknown Source)
06-27 01:45:26.309: E/AndroidRuntime(8747): at com.myapp.MainMenuFragment $ MyButtonOnClickListener.onClick(MainMenuFragment.java:52)
我做错了什么?

这里有一个类似的问题:https://dev59.com/nV_Va4cB1Zd3GeqPYOpD - adneal
如果您正在尝试创建向导,第二个<fragment>是用于什么的? - CommonsWare
我确实看到了那些链接,但不知道如何在我的情况下应用它们。 - nhaarman
@CommonsWare 第一个“Fragment”显示带有按钮“1”,“2”和“3”的第一个菜单。第二个“Fragment”显示带有按钮“1.1”,“1.2”和“1.3”的第二个菜单。计划添加第三个“Fragment”,其中包含按钮“2.1”,“2.2”和“2.3”。或者我是在错误的方向上进行着吗? - nhaarman
3个回答

18

我创建了这个主要布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="horizontal"
   tools:context="com.example.fragmentsexample.MainActivity" >

   <FrameLayout 
      android:id="@+id/contentFragment"
      android:layout_width="fill_parent" 
      android:layout_height="fill_parent" 
      android:layout_weight="1" />

</LinearLayout>

我在FrameActivity中进行了补充:

@Override
public void onCreate(Bundle savedInstanceState) {
  ...
  Fragment fragment = new Dashboard();
  FragmentManager fm = getSupportFragmentManager();
  FragmentTransaction transaction = fm.beginTransaction();
  transaction.replace(R.id.contentFragment, fragment);
  transaction.commit();
  ...
}

然后我用相同的代码替换了onClick方法,改变了Fragment(从仪表板到事件):

@Override
public void onClick.... {
  ...
  Fragment fragment = new Events();
  FragmentManager fm = getSupportFragmentManager();
  FragmentTransaction transaction = fm.beginTransaction();
  transaction.replace(R.id.contentFragment, fragment); //Container -> R.id.contentFragment
  transaction.commit();
  ...
}

16

个人而言,我不会使用任何<fragment>元素。

步骤1:在活动布局中添加一个<FrameLayout>作为向导的可变部分以及各种按钮。

步骤2:在活动的onCreate()方法中执行FragmentTransaction,将第一页向导加载到FrameLayout中。

步骤3:在“下一步”点击时,运行FragmentTransaction,将FrameLayout的内容替换为向导的下一页。

步骤4:添加适当的智能功能,以在其不可用时禁用按钮(例如,在第一页向导上后退)。

此外,您还需要考虑BACK按钮与向导中任何屏幕上的“返回”按钮如何协同工作。如果您希望它们表现相同,则需要将每个事务添加到后退堆栈中,并在处理“back”按钮时弹出后退堆栈中的内容。

如果没有人比我先做,总有一天我会尝试创建一个通过片段实现向导的示例,或者是一个可重复使用的组件。


我不确定我是否正确理解了你的意思,但是我设法让它工作了。我在我的活动布局文件中放置了一个空的<FrameLayout>。然后,在活动的onCreate()中,我调用了FragmentTransaction.add()new MainMenuFragment()添加到R.id.main_fragmentcontainer,即<FrameLayout>的ID。在MainMenuFragmentonClick()中,我创建了一个new SecondMenuFragment(),并以同样的方式再次将其添加到R.id.main_fragmentcontainer。至少这个方法可行。我特别困惑于第一步“加上你的各种按钮”。你指的是什么?我不能只使用LinearLayout吗? - nhaarman
@Niek:“你是什么意思?”——通常向导界面都有“上一步”(或“返回”)和“下一步”按钮。没有理由将它们放在片段中,因为它们在所有向导步骤中保持不变,所以我认为你应该直接将它们放在活动中。“那我不能只使用LinearLayout吗?”——用于什么? - CommonsWare
哦,那些按钮,我以为你指的是我的菜单按钮。在步骤1中,你建议使用FrameLayout,但我猜那与“下一个”和“上一个”按钮的覆盖有关。感谢你的帮助! - nhaarman
@Niek:FrameLayout 是放置片段的“插槽”。由于 FrameLayout 在处理容器方面相对较便宜,因此通常用于此目的。只要它按照您的意愿运作,任何 ViewGroup 理论上都可以使用。 - CommonsWare

0

另一个选择是使用Roman Nurik的Android-WizardPager

主要特点:

  • 分支,或者说向导步骤对后续步骤的可用性产生影响
  • 允许用户在确认之前进行回顾
  • 允许用户在向导步骤之间自由导航
  • 支持必需和可选步骤
  • 支持步骤类(从技术上讲,每个步骤都是Java类的一个实例,因此您可以在向导中拥有多个实例)

更多信息请点击这里。


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