为什么我的 Fragment 没有替换我的 Activity 布局?

问题描述:

当我从 NavigationDrawer 中选择一个项目并添加一个带有 FragmentTransaction 的新 Fragment 时,它不会替换 FragmentTransaction 的布局code>Activity 我不知道为什么!

When I pick an item from the NavigationDrawer and add a new Fragment with a FragmentTransaction it doesn't replace the layout of the Activity and I cannot figure out why!

这是我的Activity的布局:

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<FrameLayout
    android:id="@+id/content_frame"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:layout_width="match_parent"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" >
    <!-- The main content view -->

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="Location:"
        android:layout_marginTop="10dp"
        android:id="@+id/tv_disploc"
        />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="Temperature:"
        android:id="@+id/tv_disptemp"
        android:layout_below="@+id/tv_disploc"
        android:layout_marginTop="44dp" />


    <Button
        style="?android:attr/buttonStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Search"
        android:onClick="ButtonClick"
        android:id="@+id/btn_search"
        android:layout_below="@+id/et_inloc"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="37dp"
        android:layout_gravity="center" />

    <EditText
        android:layout_width="174dp"
        android:layout_height="wrap_content"
        android:id="@+id/et_inloc"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/tv_dispsearch"
        android:layout_gravity="center" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Search:"
        android:id="@+id/tv_dispsearch"
        android:layout_centerVertical="true"
        android:layout_gravity="left|center_vertical" />

    <EditText
        android:layout_width="126dp"
        android:layout_height="wrap_content"
        android:id="@+id/et_outtemp"
        android:layout_below="@+id/et_outloc"
        android:layout_toRightOf="@+id/tv_disptemp"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="30dp"
        android:clickable="false"
        android:cursorVisible="false"
        android:focusable="false"
        android:focusableInTouchMode="false"

        android:layout_gravity="center_horizontal|top" />

    <EditText
        android:layout_width="135dp"
        android:layout_height="wrap_content"
        android:id="@+id/et_outloc"
        android:layout_toRightOf="@+id/tv_disploc"
        android:layout_marginLeft="30dp"
        android:clickable="false"
        android:cursorVisible="false"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:layout_gravity="center_horizontal|top" />
</FrameLayout>

    <!-- The navigation drawer -->
    <ListView android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111"/>
</android.support.v4.widget.DrawerLayout>

这是我想要显示的Fragment:

<LinearLayout
    android:layout_height="fill_parent"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:id="@+id/fragment_option"
    android:orientation="vertical"
    android:fitsSystemWindows="true"
    android:minWidth="1000dp"
    android:minHeight="1000dp">
    android:weightSum="1">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Select your Default Location"
        android:layout_marginTop="100dp"
        android:layout_gravity="center_horizontal"
        android:id="@+id/textView" />

    <Spinner
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/spinner_locations"
        android:layout_gravity="center_horizontal" />

</LinearLayout>

谁能告诉我我在这里遗漏了什么?

Can anybody tell me what I am missing here?

我认为您可能对活动和片段有一些误解.一般规则是:

I think you might have a few misconceptions about Activities and Fragments. The general rule is:

在 Fragment 中构建您的用户界面(在大多数情况下,一个 Fragment 等于一个屏幕),然后使用活动来安排和显示那些片段.

Build your user interface in Fragments (In most cases one Fragment equals one screen) and then use Activities to arrange and display those Fragments.

带有 NavigationDrawer 的典型 Activity 布局如下所示:

A typical Activity layout with NavigationDrawer would look like this:

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- The main content view -->
    <!-- This is the placeholder for your Fragments --> 
    <!-- You can display your Fragments here with FragmentTransactions -->
    <FrameLayout
        android:id="@+id/flFragmentPlaceHolder"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- The navigation drawer -->
    <!-- It would even be better practice to use a Fragment here as well -->
    <!-- But since the Google Tutorials just use a ListView here I will as well -->
    <ListView android:id="@+id/lvDrawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111"/>

</android.support.v4.widget.DrawerLayout>

除了 Fragments 的占位符和 NavigationDrawer 的必要部分之外,没有其他东西应该在该布局中.如果您在当前状态下在 Activity 中使用该布局,除了可以从左侧拉入的 NavigationDrawer 之外,它基本上会显示一个空屏幕.您构建的任何用户界面稍后都会通过 Fragments 添加.

Nothing else besides the placeholder for the Fragments and the necessary parts of the NavigationDrawer are supposed to be in that layout. If you would use that layout in an Activity in its current state it would essentially display an empty screen besides the NavigationDrawer which can be pulled in from the left. Any user interface you build will be added later on through Fragments.

要在该布局中显示 Fragment,您必须执行 FragmentTransaction.您可以在一个 FragmentTransaction 中添加、替换、删除、显示或隐藏多个 Fragment.在上面的示例中,您可能希望向用户显示包含启动屏幕的 Fragment.要做到这一点,您可以像这样执行 FragmentTransaction:

To display a Fragment in that layout you have to perform a FragmentTransaction. You can add, replace, remove, show or hide multiple Fragments in one single FragmentTransaction. In the example above you might want to display the Fragment which contains your startup screen to the user. To do that you would perform a FragmentTransaction like this:

// It is best practice to use factory methods to create Fragment instances
final Fragment fragment = StartupFragment.newInstance();

// There are multiple `FragmentManagers`, be sure to always use the right one!
FragmentManager manager = getFragmentManager();

// This starts the `FragmentTransaction`.
FragmentTransaction transaction = manager.beginTransaction();

// Now you can define what happens in this transactions
// You can add/replace/remove/hide or show as many Fragments 
// as you want in one `FragmentTransaction`.
// This command specifically adds the Fragment to the placeholder we defined
// in the layout of the Activity
transaction.replace(R.id.flFragmentPlaceHolder, fragment);

// This commits the `FragmentTransaction`.
// Only after you call this will any changes be made
transaction.commit();

为简洁起见,与上面相同的代码也可以写成:

For brevity the same code as above can also be written as:

final Fragment fragment = StartupFragment.newInstance();
getFragmentManager().beginTransaction()
        .replace(R.id.flFragmentPlaceHolder, fragment)
        .commit();

这样编写的主要改进在于,您作为开发人员可以更快地编写它很多,因为您几乎可以一直依赖代码完成.

The main improvement of writing it like this is that you as a developer can write it a lot faster since you can rely on code completion almost the whole time.

如果稍后用户从 NavigationDrawer 中选择了一个项目,那么您只需要执行一个新的 FragmentTransaction 以将 StartupFragment 替换为不一样的!

If later on the user picks an item from the NavigationDrawer then you just have to perform a new FragmentTransaction to replace the StartupFragment with a different one!