【翻译】(4)片段

【翻译】(4)片段

 

see

http://developer.android.com/guide/topics/fundamentals/fragments.html

 

原文见

http://developer.android.com/guide/topics/fundamentals/fragments.html

 

Fragments

 

片段(注:Fragment既可以翻译为片段,也可翻译为片断,例如GLSL Fragment Shader一般就翻译为GLSL片断着色器。因为这里理解为用于显示部分内容的一种界面布局,故翻译为“片段”)

 

------------------------

 

Quickview

 

快速概览

 

* Fragments decompose application functionality and UI into reusable modules

* 片段把应用程序的功能和用户界面分解为可重用模块

* Add multiple fragments to a screen to avoid switching activities

* 添加多个片段到屏幕以避免切换活动

* Fragments have their own lifecycle, state, and back stack

* 片段拥有它们自己的生命周期,状态,和后退堆栈

* Fragments require API Level "Honeycomb" or greater

* 片段需要API级别“蜂巢”(注:即Android 3.0)或更高

 

In this document

 

本文目录

 

* Design Philosophy 设计哲学

* Creating a Fragment 创建一个片段

* Adding a user interface 添加一个用户界面

* Adding a fragment to an activity 添加一个片段到活动

* Managing Fragments 管理片段

* Performing Fragment Transactions 执行片段事务

* Communicating with the Activity 与活动通信

* Creating event callbacks to the activity 创建事件回调到活动上

* Adding items to the Action Bar 添加条目到动作栏 

* Handling the Fragment Lifecycle 处理片段生命周期

* Coordinating with the activity lifecycle 协调活动的生命周期

* Example 例子

 

Key classes

 

关键类

 

Fragment

FragmentManager

FragmentTransaction

 

Related samples

 

相关例子

 

ApiDemos API演示

 

------------------------

 

A Fragment represents a behavior or a portion of user interface in an Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running.

 

一个片段代表活动的用户界面的一个行为或一部分。你可以把多个片段组合成单一活动以构建多窗格用户界面,并且在多个活动中重用片段。你可以认为一个片段是一个活动的模块化部分,拥有它自己的生命周期,接收它自己的输入事件,并且当活动正在运行时你可以添加或删除它。

 

A fragment must always be embedded in an activity and the fragment's lifecycle is directly affected by the host activity's lifecycle. For example, when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments. However, while an activity is running (it is in the resumed lifecycle state), you can manipulate each fragment independently, such as add or remove them. When you perform such a fragment transaction, you can also add it to a back stack that's managed by the activity—each back stack entry in the activity is a record of the fragment transaction that occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards), by pressing the Back button.

 

一个片段必须总是嵌入到一个活动中,并且片段的生命周期直接受宿主活动的生命周期影响。例如,当活动被暂停,里面所有片段也会被暂停,当活动被销毁,所有片段也会被销毁。然而,当活动在运行时(它正在恢复生命周期状态),你可以单独操纵每个片段,诸如添加或删除它们。当你执行这么一个片段事务时,你还可以添加它到活动管理的后退堆栈——活动中每个后退堆栈条目是一个已发生的片段事务的记录。后退堆栈允许用户通过按后退按钮,撤销片段事务(反向向后)。

 

When you add a fragment as a part of your activity layout, it lives in a ViewGroup inside the activity's view hierarchy and defines its own layout of views. You can insert a fragment into your activity layout by declaring the fragment in the activity's layout file, as a <fragment> element, or from your application code by adding it to an existing ViewGroup. However, a fragment is not required to be a part of the activity layout; you may also use a fragment as an invisible worker for the activity.

 

当你添加一个片段作为你的活动布局的一部分时,它生存在活动视图层次内的ViewGroup中,并且定义它自己的视图布局。你可以通过在活动布局文件内声明一个片段,作为<fragment>元素,或者从你的应用程序代码中添加它到一个现存ViewGroup,插入一个片段到你的活动布局。然而,一个片段不需要是活动布局的一部分;你还可以使用一个片段作为活动的一个不可见工作者(注:后台线程)。

 

This document describes how to build your application to use fragments, including how fragments can maintain their state when added to the activity's back stack, share events with the activity and other fragments in the activity, contribute to the activity's action bar, and more.

 

本文描述如何构建你的应用程序以使用片段,包括片段当它们被添加到活动后退堆栈时如何可以维护它们的状态,如何与活动和活动中的其它片段共享事件,如何投放到活动的动作栏,等等。

 

-------------------------------

 

Design Philosophy

 

设计哲学

 

Android introduced fragments in Android 3.0 (API Level "Honeycomb"), primarily to support more dynamic and flexible UI designs on large screens, such as tablets. Because a tablet's screen is much larger than that of a mobile phone, there's more room to combine and interchange UI components. Fragments allow such designs without the need for you to manage complex changes to the view hierarchy. By dividing the layout of an activity into fragments, you become able to modify the activity's appearance at runtime and preserve those changes in a back stack that's managed by the activity.

 

Android在Android 3.0(API级别“蜂巢”)中引入片段,主要是为了在大屏幕中支持更动态和更灵活用户界面设计,诸如平板电脑。因为平板电脑的屏幕远大于移动电话,有更多空间组合和交换用户界面组件。片段允许这样的设计,而不需要你管理视图层次的复杂改变。通过把活动布局划分为片段,你就有能力在运行时修改活动的外观,并且把那些改变保存在活动管理的后退堆栈中。

 

For example, a news application can use one fragment to show a list of articles on the left and another fragment to display an article on the right—both fragments appear in one activity, side by side, and each fragment has its own set of lifecycle callback methods and handle their own user input events. Thus, instead of using one activity to select an article and another activity to read the article, the user can select an article and read it all within the same activity, as illustrated in figure 1.

 

例如,一个新闻应用程序可以使用一个片段在左侧展示文章列表,而另一个片段在右侧显示一篇文章——两个片段显示在一个活动中,一个挨一个,而每个活动拥有它自己的生命周期回调方法集合并且处理它们自己的用户输入事件。这样,不需要使用一个活动来选择文章而用另一个活动阅读文章,取而代之的是,用户可以完全在相同活动中选择文章并且阅读它,正如图1所描绘的那样。

 

(图略,

左:活动A 活动B

右:带两个片段的活动

 

Figure 1. An example of how two UI modules that are typically separated into two activities can be combined into one activity, using fragments.

 

图1. 一个例子,演示典型地被分割成两个活动的两个用户界面模块,可以用片段组合成一个活动。

 

A fragment should be a modular and reusable component in your application. That is, because the fragment defines its own layout and its own behavior using its own lifecycle callbacks, you can include one fragment in multiple activities. This is especially important because it allows you to adapt your user experience to different screen sizes. For instance, you might include multiple fragments in an activity only when the screen size is sufficiently large, and, when it is not, launch separate activities that use different fragments.

 

一个片段应该是你的应用程序中一个模块化和可重用组件。就是说,因为片段定义它自己的布局和它自己的行为,使用它自己的生命周期回调,所以你可以在多个活动中包含同一个片段。这特别重要,因为这允许你让你的用户体验适应不同的屏幕大小。例如,你可以包含多个片段到一个活动中,仅当屏幕大小足够大,而当屏幕不够大时,启动使用不同片段的独立活动。

 

For example—to continue with the news application example—the application can embed two fragments in Activity A, when running on an extra large screen (a tablet, for example). However, on a normal-sized screen (a phone, for example), there's not enough room for both fragments, so Activity A includes only the fragment for the list of articles, and when the user selects an article, it starts Activity B, which includes the fragment to read the article. Thus, the application supports both design patterns suggested in figure 1.

 

例如——继续前面的新闻应用程序例子——当运行在一个特别大屏幕(例如平板电脑)时,应用程序可以在活动A嵌入两个片段。然而,在一个普通大小屏幕(例如手机),没有足够的空间给两个片段,所以活动A只包含文章列表的片段,而当用户选择一个文章时,它启动包含用来阅读文章的片段的活动B。这样,应用程序支持图1中建议的两种设计模式。

 

-------------------------------

 

Creating a Fragment

 

创建片段

 

(图略)

 

1. Fragment is added 

片段被添加

2. onAttach()

3. onCreate()

4. onCreateView()

5. onActivityCreated()

6. onStart()

7. onResume()

8. Fragment is active

片段被激活

9-1. User navigates backward or fragment is removed/replaced

用户导航向后或片段被移除/替换

9-2. Fragment is added to the back stack, then removed/replaced

片段被添加到后退堆栈,然后被移除/替换

10. onPause()

11. onStop()

12. onDestrooyView() 

13-1. onDestroy() -> 14

13-2. The fragment returns to the layout from the back stack -> 4

片段退回到回退堆栈中的布局

14. onDetach()

15. Fragment is destroyed

片段被销毁

 

Figure 2. The lifecycle of a fragment (while its activity is running).

 

图2. 片段的生命周期(当它的活动正在运行)。

 

To create a fragment, you must create a subclass of Fragment (or an existing subclass of it). The Fragment class has code that looks a lot like an Activity. It contains callback methods similar to an activity, such as onCreate(), onStart(), onPause(), and onStop(). In fact, if you're converting an existing Android application to use fragments, you might simply move code from your activity's callback methods into the respective callback methods of your fragment.

 

为了创建一个片段,你必须创建Fragment(或它的现存子类)的子类。Fragment类的代码看起来很像Activity。它包含类似于活动的回调方法,诸如onCreate(),onStart(),onPause(),和onStop()。实际上,如果你正在转换一个现存的Android应用程序以使用片段,你可以简单地移动来自你的活动回调方法的代码到你的片段的相应回调方法内。

 

Usually, you should implement at least the following lifecycle methods:

 

通常,你至少应该实现以下生命周期方法:

 

onCreate()

 

The system calls this when creating the fragment. Within your implementation, you should initialize essential components of the fragment that you want to retain when the fragment is paused or stopped, then resumed.

 

当创建片段时系统调用它。在你的实现内,你应该初始化当片段被暂停或停止然后恢复时,你希望能保持的片段的内部组件。

 

onCreateView()

 

The system calls this when it's time for the fragment to draw its user interface for the first time. To draw a UI for your fragment, you must return a View from this method that is the root of your fragment's layout. You can return null if the fragment does not provide a UI.

 

当片段第一次重绘其用户界面的时候系统调用它。为了绘画你的片段的用户界面,你必须从这个方法内返回一个View,它是你的片段布局的根。你可以返回null,如果片段没有提供用户界面。

 

onPause()

 

The system calls this method as the first indication that the user is leaving the fragment (though it does not always mean the fragment is being destroyed). This is usually where you should commit any changes that should be persisted beyond the current user session (because the user might not come back).

 

系统调用这个方法作为首个指示,表示用户离开片段(虽然它不总是意味着片段被销毁)。在那里你通常应该提交任何应该超越当前用户会话而被持久化的改变(因为用户不可能时光倒流)。

 

Most applications should implement at least these three methods for every fragment, but there are several other callback methods you should also use to handle various stages of the fragment lifecycle. All the lifecycle callback methods are discussed more later, in the section about Handling the Fragment Lifecycle.

 

大多数应用程序对于每个片段至少应该实现这三个方法,但你还应该使用其它几个方法处理片段生命周期的不同阶段。所有生命周期回调方法在下面关于处理片段生命周期的章节中详细讨论。

 

There are also a few subclasses that you might want to extend, instead of the base Fragment class:

 

还有你可能希望要继承的的几个子类,取代基本的Fragment类:

 

DialogFragment

 

Displays a floating dialog. Using this class to create a dialog is a good alternative to using the dialog helper methods in the Activity class, because you can incorporate a fragment dialog into the back stack of fragments managed by the activity, allowing the user to return to a dismissed fragment.

 

显示一个浮动对话框。使用这个类创建对话框是代替使用Activity的对话框辅助方法的很好的替换品,因为你可以把一个片段对话框加入到由活动管理的片段的后退堆栈中,允许用户返回到一个已离开的片段。

 

ListFragment

 

Displays a list of items that are managed by an adapter (such as a SimpleCursorAdapter), similar to ListActivity. It provides several methods for managing a list view, such as the onListItemClick() callback to handle click events.

 

显示一个由适配器(诸如SimpleCursorAdapter)管理的条目列表,类似于ListActivity。它提供几个方法管理列表视图,诸如onListItemClick()回调方法是用来管理点击事件。

 

PreferenceFragment

 

Displays a hierarchy of Preference objects as a list, similar to PreferenceActivity. This is useful when creating a "settings" activity for your application.

 

显示Preference对象的层次作为一个列表,类似于PreferenceActivity。当为你的应用程序创建“设置”活动时有用。

 

Adding a user interface

 

添加一个用户界面

 

A fragment is usually used as part of an activity's user interface and contributes its own layout to the activity.

 

一个片段通常用作一个活动的用户界面的一部分,并且向活动提供它自己的布局。

 

To provide a layout for a fragment, you must implement the onCreateView() callback method, which the Android system calls when it's time for the fragment to draw its layout. Your implementation of this method must return a View that is the root of your fragment's layout.

 

为了提供一个片段的布局,你必须实现onCreateView()回调方法,当片段绘画其布局时Android系统调用它。你对这个方法的实现必须返回一个View,它是你的片段布局的根。

 

-------------------------------

 

Note: If your fragment is a subclass of ListFragment, the default implementation returns a ListView from onCreateView(), so you don't need to implement it.

 

注意:如果你的片段是ListFragment的子类,默认实现从onCreateView()内返回一个ListView,所以你不需要实现它。

 

-------------------------------

 

To return a layout from onCreateView(), you can inflate it from a layout resource defined in XML. To help you do so, onCreateView() provides a LayoutInflater object.

 

为了从onCreateView()内返回一个布局,你可以从定义在XML的布局资源中解压它。为了帮助你做到这一点,onCreateView()提供一个LayoutInflater对象。

 

For example, here's a subclass of Fragment that loads a layout from the example_fragment.xml file:

 

例如,这里有一个Fragment子类,从example_fragment.xml文件中加载布局。

 

-------------------------------

 

public static class ExampleFragment extends Fragment {

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container,

                             Bundle savedInstanceState) {

        // Inflate the layout for this fragment

        // 为这个片段解压布局

        return inflater.inflate(R.layout.example_fragment, container, false);

    }

}

 

-------------------------------

 

-------------------------------

Creating a layout

 

创建布局

 

In the sample above, R.layout.example_fragment is a reference to a layout resource named example_fragment.xml saved in the application resources. For information about how to create a layout in XML, see the User Interface documentation.

 

在上面的例子中,R.layout.example_fragment是指向保存在应用资源内名为example_fragment.xml的布局资源的引用。关于如何在XML内创建布局的信息,请参看用户界面文档。

 

-------------------------------

 

The container parameter passed to onCreateView() is the parent ViewGroup (from the activity's layout) in which your fragment layout will be inserted. The savedInstanceState parameter is a Bundle that provides data about the previous instance of the fragment, if the fragment is being resumed (restoring state is discussed more in the section about Handling the Fragment Lifecycle).

 

传递给onCreateView()的container参数是父级ViewGroup(来自活动的布局),它是你的片段布局将被插入的地方。savedInstanceState参数是一个Bundle对象,提供关于前一个片段实例的数据,如果片段正在被恢复(在关于处理片段生命周期的章节中会更详细地讨论状态的恢复)。

 

The inflate() method takes three arguments:

 

inflate()方法取三个参数:

 

* The resource ID of the layout you want to inflate.

 

* 你想解压的布局的资源ID

 

* The ViewGroup to be the parent of the inflated layout. Passing the container is important in order for the system to apply layout parameters to the root view of the inflated layout, specified by the parent view in which it's going.

 

* ViewGroup是被解压布局的父级。传递容器对于系统应用布局参数到被解压布局的,由它要出现的父级视图指定的根视图十分重要。

 

* A boolean indicating whether the inflated layout should be attached to the ViewGroup (the second parameter) during inflation. (In this case, this is false because the system is already inserting the inflated layout into the container—passing true would create a redundant view group in the final layout.)

 

* 一个布尔值指示被解压布局是否应该在解压期间依附到ViewGroup(第二参数)。(在这种情况下,它是false,因为系统总是把被解压布局插入容器——传递true将在最终布局内创建一个冗余的视图组)

 

Now you've seen how to create a fragment that provides a layout. Next, you need to add the fragment to your activity.

 

现在你已经看到如何创建提供布局的片段。接下来,你需要添加片段到你的活动。

 

Adding a fragment to an activity

 

添加片段到活动

 

Usually, a fragment contributes a portion of UI to the host activity, which is embedded as a part of the activity's overall view hierarchy. There are two ways you can add a fragment to the activity layout:

 

通常,一个片段提供用户界面的一部分给宿主活动,它被嵌入作为活动整个视图层次的一部分。你有两种方式添加片段到活动布局:

 

* Declare the fragment inside the activity's layout file.

 

* 在活动布局文件内声明片段:

 

In this case, you can specify layout properties for the fragment as if it were a view. For example, here's the layout file for an activity with two fragments:

 

这种情况下,你可以指定片段的布局属性,就像它是一个视图。例如,这里是活动的布局文件,带有两个片段:

 

-------------------------------

 

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="horizontal"

    android:layout_width="match_parent"

    android:layout_height="match_parent">

    <fragment android:name="com.example.news.ArticleListFragment"

            android:id="@+id/list"

            android:layout_weight="1"

            android:layout_width="0dp"

            android:layout_height="match_parent" />

    <fragment android:name="com.example.news.ArticleReaderFragment"

            android:id="@+id/viewer"

            android:layout_weight="2"

            android:layout_width="0dp"

            android:layout_height="match_parent" />

</LinearLayout>

 

-------------------------------

 

The android:name attribute in the <fragment> specifies the Fragment class to instantiate in the layout.

 

<fragment>内的android:name属性指定要在布局内实例化的Fragment类。

 

When the system creates this activity layout, it instantiates each fragment specified in the layout and calls the onCreateView() method for each one, to retrieve each fragment's layout. The system inserts the View returned by the fragment directly in place of the <fragment> element.

 

当系统创建这个活动布局时,它实例化布局内指定的每个片段并且对每个片段调用onCreateView()方法,以取出每个片段的布局。系统直接把<fragment>元素位置上的片段插入要返回的视图。

 

-------------------------------

 

Note: Each fragment requires a unique identifier that the system can use to restore the fragment if the activity is restarted (and which you can use to capture the fragment to perform transactions, such as remove it). There are three ways to provide an ID for a fragment:

 

注意:每个片段需要一个唯一标识符,系统可以使用它恢复片段,如果活动被重启(而且你可以使用它捕获片段以执行事务,诸如移除它)。有三种提供片段的ID的方式:

 

* Supply the android:id attribute with a unique ID.

 

* 用一个唯一ID提供android:id属性。

 

* Supply the android:tag attribute with a unique string.

 

* 用一个唯一字符串提供android:tag属性。

 

* If you provide neither of the previous two, the system uses the ID of the container view.

 

* 如果你没有提供前两种方式中的一种,系统使用容器视图的ID。

 

-------------------------------

 

* Or, programmatically add the fragment to an existing ViewGroup.

 

或者,用程序添加片段到一个现存ViewGroup。

 

At any time while your activity is running, you can add fragments to your activity layout. You simply need to specify a ViewGroup in which to place the fragment.

 

在你的活动正在运行的任何时候,你可以添加片段到你的活动布局。你简单地需要指定一个ViewGroup,其中放置你的片段。

 

To make fragment transactions in your activity (such as add, remove, or replace a fragment), you must use APIs from FragmentTransaction. You can get an instance of FragmentTransaction from your Activity like this:

 

为了执行你的活动内的片段事务(诸如添加、移除、或替换片段),你必须使用FragmentTransaction的API。你可以从你的Activity(注:活动)中获取FragmentTransaction实例,就像这样:

 

-------------------------------

 

FragmentManager fragmentManager = getFragmentManager()

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

 

-------------------------------

 

You can then add a fragment using the add() method, specifying the fragment to add and the view in which to insert it. For example:

 

然后你可以使用add()方法添加片段,指定要添加的片段和要插入它的视图。例如:

 

-------------------------------

 

ExampleFragment fragment = new ExampleFragment();

fragmentTransaction.add(R.id.fragment_container, fragment);

fragmentTransaction.commit();

 

-------------------------------

 

The first argument passed to add() is the ViewGroup in which the fragment should be placed, specified by resource ID, and the second parameter is the fragment to add.

 

传递给add()的第一参数是ViewGroup对象,片段应该在其中被替换,由资源ID指定,而第二参数是要添加的片段。

 

Once you've made your changes with FragmentTransaction, you must call commit() for the changes to take effect.

 

一旦你对FragmentTransaction做出改变,你必须调用commit()使改变生效。

 

Adding a fragment without a UI

 

添加一个没有用户界面的片段

 

The examples above show how to add a fragment to your activity in order to provide a UI. However, you can also use a fragment to provide a background behavior for the activity without presenting additional UI.

 

上面的实例展示如何添加片段到你的活动以提供用户界面。然而,你还可以使用一个片段为活动提供后台行为,而不呈现额外的用户界面。

 

To add a fragment without a UI, add the fragment from the activity using add(Fragment, String) (supplying a unique string "tag" for the fragment, rather than a view ID). This adds the fragment, but, because it's not associated with a view in the activity layout, it does not receive a call to onCreateView(). So you don't need to implement that method.

 

为了添加没有用户界面的片段,使用add(Fragment, String)在活动中添加片段(为片段提供一个唯一字符串标签,而非一个视图ID)。但是,这样添加片段的话,因为它没有关联到一个活动布局的视图,所以它不会接收到onCreateView()的调用。因此你不需要实现那个方法。

 

Supplying a string tag for the fragment isn't strictly for non-UI fragments—you can also supply string tags to fragments that do have a UI—but if the fragment does not have a UI, then the string tag is the only way to identify it. If you want to get the fragment from the activity later, you need to use findFragmentByTag().

 

对片段应用一个字符串标签对于非用户界面的片段不是严格要求的——你也可以提供字符串标签给有用户界面的片段——但如果片段没有用户界面,那么字符串标签是标识它的唯一方式。如果稍后你想从活动中获取片段,你需要使用findFragmentByTag()。

 

For an example activity that uses a fragment as a background worker, without a UI, see the FragmentRetainInstance.java sample.

 

要获取使用片段作为后台工作者的片段的示例活动,请参看FragmentRetainInstance.java示例。

 

-------------------------------

 

Managing Fragments

 

管理片段

 

To manage the fragments in your activity, you need to use FragmentManager. To get it, call getFragmentManager() from your activity.

 

为了管理在你的活动内的片段,你需要使用FragmentManager。为了获得它,可以从你的活动调用getFragmentManager()。

 

Some things that you can do with FragmentManager include:

 

用FragmentManager你可以做一些事情,包括:

 

* Get fragments that exist in the activity, with findFragmentById() (for fragments that provide a UI in the activity layout) or findFragmentByTag() (for fragments that do or don't provide a UI).

 

* 使用findFragmentById()获取存在于活动内的片段(针对在活动布局内提供用户界面的片段)或findFragmentByTag()(针对提供或不提供用户界面的片段)

 

* Pop fragments off the back stack, with popBackStack() (simulating a Back command by the user).

 

* 使用popBackStack()(模拟用户的后退命令)把片段弹出后退堆栈。

 

* Register a listener for changes to the back stack, with addOnBackStackChangedListener().

 

* 使用addOnBackStackChangedListener()注册一个针对后退堆栈改变的监听器。

 

For more information about these methods and others, refer to the FragmentManager class documentation.

 

更多关于这些方法和其它东西的信息,请参照FragmentManager类文档。

 

As demonstrated in the previous section, you can also use FragmentManager to open a FragmentTransaction, which allows you to perform transactions, such as add and remove fragments.

 

正如前面章节所演示的,你还可以使用FragmentManager打开FragmentTransaction,它允许你执行事务,诸如添加和移除片段。

 

-------------------------------

 

Performing Fragment Transactions

 

执行片段事务

 

A great feature about using fragments in your activity is the ability to add, remove, replace, and perform other actions with them, in response to user interaction. Each set of changes that you commit to the activity is called a transaction and you can perform one using APIs in FragmentTransaction. You can also save each transaction to a back stack managed by the activity, allowing the user to navigate backward through the fragment changes (similar to navigating backward through activities).

 

关于活动内片段的一个重大特性是有能力对它们执行添加、移除、替换、以及其它动作,响应用户交互。你提交给活动的每组改变被称为事务而你可以用FragmentTransaction内的API执行它。你还可以保存任意事务到活动管理的后退堆栈,允许用户在会话改变之间导航后退(类似于在活动间导航后退)。

 

You can acquire an instance of FragmentTransaction from the FragmentManager like this:

 

你可以从FragmentManager取得FragmentTransaction实例,像这样:

 

-------------------------------

 

FragmentManager fragmentManager = getFragmentManager();

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

 

-------------------------------

 

Each transaction is a set of changes that you want to perform at the same time. You can set up all the changes you want to perform for a given transaction using methods such as add(), remove(), and replace(). Then, to apply the transaction to the activity, you must call commit().

 

每个事务是你希望同时执行的一组改变。你可以通过使用诸如add(),remove(),和replace()的方法,对一个给定的事务设置你想执行的所有改变。然后,为了应用事务到活动,你必须调用commit()。

 

Before you call commit(), however, you might want to call addToBackStack(), in order to add the transaction to a back stack of fragment transactions. This back stack is managed by the activity and allows the user to return to the previous fragment state, by pressing the Back button.

 

然而,在你调用commit()之前,为了添加事务到片段事务的回退堆栈,你可能希望调用addToBackStack()。这个后退堆栈被活动管理,允许用户通过按后退按钮,返回到前一个片段状态。

 

For example, here's how you can replace one fragment with another, and preserve the previous state in the back stack:

 

例如,这是你如何可以用一个片段替换另一个片段,并且在后退堆栈内保留前一个状态:

 

-------------------------------

 

// 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

// 用这个片段替换fragment_container视图中的所有东西,

// 并且添加事务到后退堆栈

transaction.replace(R.id.fragment_container, newFragment);

transaction.addToBackStack(null);

 

// Commit the transaction

// 提交事务

transaction.commit();

 

-------------------------------

 

In this example, newFragment replaces whatever fragment (if any) is currently in the layout container identified by the R.id.fragment_container ID. By calling addToBackStack(), the replace transaction is saved to the back stack so the user can reverse the transaction and bring back the previous fragment by pressing the BACK button.

 

在这个例子中,newFragment替换当前在R.id.fragment_container标识的布局容器内的任意片段(如果有)。通过调用addToBackStack(),替换事务被保存到回退堆栈,所以用户可以逆向执行事务并且通过按后退按钮返回到前一个片段。

 

If you add multiple changes to the transaction (such as another add() or remove()) and call addToBackStack(), then all changes applied before you call commit() are added to the back stack as a single transaction and the Back button will reverse them all together.

 

如果你添加多个改变到事务(诸如另一个add()或remove())以及调用addToBackStack(),那么在你调用commit()前的应用的所有改变被添加到后退堆栈作为单一事务,而后退按钮将一起全部逆向执行它们。

 

The order in which you add changes to a FragmentTransaction doesn't matter, except:

 

你添加改变到FragmentTransaction的顺序是不重要的,除了:

 

* You must call commit() last

 

* 你必须最后调用commit()

 

* If you're adding multiple fragments to the same container, then the order in which you add them determines the order they appear in the view hierarchy

 

* 如果你正在添加多个片段到相同的容器,那么你添加它们的顺序决定它们显示在视图层次内的顺序。

 

If you do not call addToBackStack() when you perform a transaction that removes a fragment, then that fragment is destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and will be resumed if the user navigates back.

 

如果当你执行移除片段的事务时你没有调用addToBackStack(),那么在事务提交并且用户没有向后导航回到此片段时片段会被销毁。然而,如果你在移除片段时调用addToBackStack(),那么片段被停止并被恢复,如果用户导航回来。

 

-------------------------------

 

Tip: For each fragment transaction, you can apply a transition animation, by calling setTransition() before you commit.

 

提示:对于每个片段事务,你可以通过在你提交前调用setTransition(),应用一个过渡动画。

 

-------------------------------

 

Calling commit() does not perform the transaction immediately. Rather, it schedules it to run on the activity's UI thread (the "main" thread) as soon as the thread is able to do so. If necessary, however, you may call executePendingTransactions() from your UI thread to immediately execute transactions submitted by commit(). Doing so is usually not necessary unless the transaction is a dependency for jobs in other threads.

 

调用commit()不会立刻执行事务。然而,在活动的用户界面线程(主线程)调度它,一旦该线程能这样做。然而,如果有需要,你可以从你的用户界面线程内调用executePendingTransactions()以立刻执行由commit()提交的事务。这样做通常不是必须的,除非该事务是其它线程工作的依赖。

 

-------------------------------

 

Caution: You can commit a transaction using commit() only prior to the activity saving its state (when the user leaves the activity). If you attempt to commit after that point, an exception will be thrown. This is because the state after the commit can be lost if the activity needs to be restored. For situations in which its okay that you lose the commit, use commitAllowingStateLoss().

 

小心:你可以用commit()提交一个事务,仅仅早于活动保存其状态(当用户离开活动时)。如果你尝试在那个时间点之后提交,将抛出异常。这是因为提交后的状态可能被丢失,如果活动需要被恢复。为了获知你丢失提交是允许的情况,请使用commitAllowingStateLoss()。

 

-------------------------------

 

-------------------------------

 

Communicating with the Activity

 

与活动通信

 

Although a Fragment is implemented as an object that's independent from an Activity and can be used inside multiple activities, a given instance of a fragment is directly tied to the activity that contains it.

 

虽然片段被实现为独立于活动的对象,并且可以用于多个活动内部,但一个给定的片段实例被直接地关联到容纳它的活动。

 

Specifically, the fragment can access the Activity instance with getActivity() and easily perform tasks such as find a view in the activity layout:

 

特别地,片段可以用getActivity()访问活动实例并且轻易地执行某些任务诸如在活动布局中查找视图:

 

-------------------------------

 

View listView = getActivity().findViewById(R.id.list);

 

-------------------------------

 

Likewise, your activity can call methods in the fragment by acquiring a reference to the Fragment from FragmentManager, using findFragmentById() or findFragmentByTag(). For example:

 

同样,你的活动可以通过使用findFragmentById()或findFragmentByTag(),从FragmentManager获取片段的引用,调用片段的方法。例如:

 

-------------------------------

 

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);

 

-------------------------------

 

Creating event callbacks to the activity

 

创建活动的事件回调

 

In some cases, you might need a fragment to share events with the activity. A good way to do that is to define a callback interface inside the fragment and require that the host activity implement it. When the activity receives a callback through the interface, it can share the information with other fragments in the layout as necessary.

 

在一些情况下,你可能需要让一个片段与活动共享事件。可以做的较好方式是在片段内定义一个活动接口,并且要求宿主活动实现它。当活动通过接口接收到一个活动,它可以在需要时与布局内的其它片段共享信息。

 

For example, if a news application has two fragments in an activity—one to show a list of articles (fragment A) and another to display an article (fragment B)—then fragment A must tell the activity when a list item is selected so that it can tell fragment B to display the article. In this case, the OnArticleSelectedListener interface is declared inside fragment A:

 

例如,如果新闻应用程序在一个活动中拥有两个片段——一个用来显示文章列表(片段A)而另一个片段显示文章(片段B)——那么当列表项被选中时片段A必须告诉活动,使它可以叫片段B去显示文章。在这种情况下,OnArticleSelectedListener接口被定义在片段A内:

 

-------------------------------

 

public static class FragmentA extends ListFragment {

    ...

    // Container Activity must implement this interface

    // 容器活动必须实现此接口

    public interface OnArticleSelectedListener {

        public void onArticleSelected(Uri articleUri);

    }

    ...

}

 

-------------------------------

 

Then the activity that hosts the fragment implements the OnArticleSelectedListener interface and overrides onArticleSelected() to notify fragment B of the event from fragment A. To ensure that the host activity implements this interface, fragment A's onAttach() callback method (which the system calls when adding the fragment to the activity) instantiates an instance of OnArticleSelectedListener by casting the Activity that is passed into onAttach():

 

然后持有片段的活动实现OnArticleSelectedListener接口并且覆盖onArticleSelected(),用来自片段A的事件通知片段B。为了确保宿主活动实现此接口,片段A的onAttach()回调方法(系统在添加片段到活动时调用它),通过转换传递进onAttach()的Activity对象,实例化一个OnArticleSelectedListener实例。

 

-------------------------------

 

public static class FragmentA extends ListFragment {

    OnArticleSelectedListener mListener;

    ...

    @Override

    public void onAttach(Activity activity) {

        super.onAttach(activity);

        try {

            mListener = (OnArticleSelectedListener) activity;

        } catch (ClassCastException e) {

            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");

        }

    }

    ...

}

 

-------------------------------

 

If the activity has not implemented the interface, then the fragment throws a ClassCastException. On success, the mListener member holds a reference to activity's implementation of OnArticleSelectedListener, so that fragment A can share events with the activity by calling methods defined by the OnArticleSelectedListener interface. For example, if fragment A is an extension of ListFragment, each time the user clicks a list item, the system calls onListItemClick() in the fragment, which then calls onArticleSelected() to share the event with the activity:

 

如果活动没有实现接口类,那么片段抛出ClassCastException。成功的话,mListener成员变量持有活动的OnArticleSelectedListener实现的引用,致使片段A可以通过调用定义在OnArticleSelectedListener接口类的方法与活动共享事件。例如,如果片段A是ListFragment的扩展(注:子类),每当用户点击列表项,系统调用片段内的onListItemClick(),然后它调用onArticleSelected()与活动共享事件:

 

-------------------------------

 

public static class FragmentA extends ListFragment {

    OnArticleSelectedListener mListener;

    ...

    @Override

    public void onListItemClick(ListView l, View v, int position, long id) {

        // Append the clicked item's row ID with the content provider Uri

        // 用内容提供者的URI添加点击项的行ID

        Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);

        // Send the event and Uri to the host activity

        // 发送事件和URI到宿主活动

        mListener.onArticleSelected(noteUri);

    }

    ...

}

 

-------------------------------

 

The id parameter passed to onListItemClick() is the row ID of the clicked item, which the activity (or other fragment) uses to fetch the article from the application's ContentProvider.

 

传递给onListItemClick()的id参数是选中条目的行ID,活动(或其它片段)使用它获取应用程序的ContentProvider的文章。

 

More information about using a content provider is available in the Content Providers document.

 

更多关于使用内容提供者的信息在内容提供者文档中可用。

 

Adding items to the Action Bar

 

添加条目到动作栏

 

Your fragments can contribute menu items to the activity's Options Menu (and, consequently, the Action Bar) by implementing onCreateOptionsMenu(). In order for this method to receive calls, however, you must call setHasOptionsMenu() during onCreate(), to indicate that the fragment would like to add items to the Options Menu (otherwise, the fragment will not receive a call to onCreateOptionsMenu()).

 

你的片段可以通过实现onCreateOptionsMenu(),对活动的选项菜单(以及,因此影响到的动作栏)提供菜单条目。然而,为了让这个方法接收到调用,你必须在onCreate()期间调用setHasOptionsMenu(),以指示片段将打算添加条目到选项菜单(否则,片段将不会接收到对onCreateOptionsMenu()的调用)。

 

Any items that you then add to the Options Menu from the fragment are appended to the existing menu items. The fragment also receives callbacks to onOptionsItemSelected() when a menu item is selected.

 

然后你添加到片段的选项菜单的任何条目,被添加到现存的菜单条目。当菜单条目被选中时,片段还接收到对onOptionsItemSelected()的回调。

 

You can also register a view in your fragment layout to provide a context menu by calling registerForContextMenu(). When the user opens the context menu, the fragment receives a call to onCreateContextMenu(). When the user selects an item, the fragment receives a call to onContextItemSelected().

 

你还可以在你的片段布局中注册一个视图以提供一个上下文菜单,通过调用registerForContextMenu()。当用户打开上下文菜单时,片段接收一个对onCreateContextMenu()的调用。当用户选择一个条目时,片段接收对onContextItemSelected()的调用。

 

-------------------------------

 

Note: Although your fragment receives an on-item-selected callback for each menu item it adds, the activity is first to receive the respective callback when the user selects a menu item. If the activity's implementation of the on-item-selected callback does not handle the selected item, then the event is passed to the fragment's callback. This is true for the Options Menu and context menus.

 

注意:虽然你的片段为它添加的每个菜单接收一个条目选中的回调,但是当用户选择一个菜单项时,活动首先要接收相应的回调。如果活动对条目选中的实现没有处理选中的条目,那么事件被传递到片段的回调。选项菜单和上下文菜单就是这样。

 

-------------------------------

 

For more information about menus, see the Menus and Action Bar developer guides.

 

更多关于菜单的信息,请参考菜单和动作栏开发者指引。

 

-------------------------------

 

Handling the Fragment Lifecycle

 

处理片段生命周期

 

活动状态、片段回调

1. 被创建

onAttach()

onCreate()

onCreateView()

onActivityCreate()

2. 被启动

onStart()

3. 被恢复

onResume()

4. 被暂停

onPause()

5. 被停止

onStop()

6. 被销毁

onDestroyView()

onDestroy()

onDetach()

 

(图略)

 

Figure 3. The activity lifecycle's affect on the fragment lifecycle.

 

图3. 活动生命周期对片段生命周期的影响。

 

Managing the lifecycle of a fragment is a lot like managing the lifecycle of an activity. Like an activity, a fragment can exist in three states:

 

管理片段的生命周期非常像管理活动的生命周期。类似于一个活动,一个片段可以存在于三种状态。

 

* Resumed

 

* 被恢复

 

The fragment is visible in the running activity.

 

片段在运行中的活动中可见。

 

* Paused

 

* 被暂停

 

Another activity is in the foreground and has focus, but the activity in which this fragment lives is still visible (the foreground activity is partially transparent or doesn't cover the entire screen).

 

另一个活动在前台并且拥有焦点,但片段居住的活动仍然可见(前台活动部分透明或没有覆盖整个屏幕)。

 

* Stopped

 

* 被停止

 

The fragment is not visible. Either the host activity has been stopped or the fragment has been removed from the activity but added to the back stack. A stopped fragment is still alive (all state and member information is retained by the system). However, it is no longer visible to the user and will be killed if the activity is killed.

 

片段不可见,宿主活动被停止或片段从互动中移除但添加到后退堆栈。一个被停止的片段仍然是存活的(所有状态和成员变量信息被系统保持)。然而,它对于用户不再可见,如果活动被杀死它也将被杀死。

 

Also like an activity, you can retain the state of a fragment using a Bundle, in case the activity's process is killed and you need to restore the fragment state when the activity is recreated. You can save the state during the fragment's onSaveInstanceState() callback and restore it during either onCreate(), onCreateView(), or onActivityCreated(). For more information about saving state, see the Activities document.

 

还有像活动那样,你可以使用一个Bundle保持片段的状态,一旦活动的进程被杀死而你需要在活动被重新创建时恢复片段的状态。你可以在片段的onSaveInstanceState()回调期间保存状态,并且在onCreate(),onCreateView(),或onActivityCreated()期间恢复它。更多关于保存状态的信息,请参考活动文档。

 

The most significant difference in lifecycle between an activity and a fragment is how one is stored in its respective back stack. An activity is placed into a back stack of activities that's managed by the system when it's stopped, by default (so that the user can navigate back to it with the Back button, as discussed in Tasks and Back Stack). However, a fragment is placed into a back stack managed by the host activity only when you explicitly request that the instance be saved by calling addToBackStack() during a transaction that removes the fragment.

 

在活动和片段生命周期之间最重要的区别是它是如何保存在它对应的回退堆栈中。一个活动,当它被停止时,默认放入由系统管理的活动后退堆栈中(以致使用户可以用后退按钮导航退回到它,正如任务和后退堆栈中讨论的那样)。然而,一个片段被放入由宿主活动管理的后退堆栈,仅当你通过在移除片段的事务期间调用addToBackStack()显式要求实例要被保存。

 

Otherwise, managing the fragment lifecycle is very similar to managing the activity lifecycle. So, the same practices for managing the activity lifecycle also apply to fragments. What you also need to understand, though, is how the life of the activity affects the life of the fragment.

 

除此以外,片段生命周期的管理类似于活动生命周期的管理。所以,管理活动生命周期的相同实践同样应用在片段上。虽然如此,你还需要理解,活动的生命周期是如何影响活动的生命周期。

 

Coordinating with the activity lifecycle

 

协调活动生命周期

 

The lifecycle of the activity in which the fragment lives directly affects the lifecycle of the fragment, such that each lifecycle callback for the activity results in a similar callback for each fragment. For example, when the activity receives onPause(), each fragment in the activity receives onPause().

 

片段寄居的活动的生命周期直接影响片段的活动生命周期,以致活动的每个声明周期活动导致每个片段的相似回调。例如,当活动接收到onPause(),活动内的每个片段都会接收到onPause()。

 

Fragments have a few extra lifecycle callbacks, however, that handle unique interaction with the activity in order to perform actions such as build and destroy the fragment's UI. These additional callback methods are:

 

然而,片段拥有一些额外的声明周期回调,处理与活动的唯一交互,以执行一些动作诸如构建和销毁片段用户界面。这些额外的回调方法是:

 

* onAttach()

 

Called when the fragment has been associated with the activity (the Activity is passed in here).

 

当片段被关联到活动时调用(活动在这里被传递进来)

 

* onCreateView()

 

Called to create the view hierarchy associated with the fragment.

 

调用以创建关联片段的视图层次。

 

* onActivityCreated()

 

Called when the activity's onCreate() method has returned.

 

当活动的onCreate()方法返回时创建。

 

* onDestroyView()

 

Called when the view hierarchy associated with the fragment is being removed.

 

当关联到片段的视图层次被移除。

 

* onDetach()

 

Called when the fragment is being disassociated from the activity.

 

当解除片段与活动的关联时调用。

 

The flow of a fragment's lifecycle, as it is affected by its host activity, is illustrated by figure 3. In this figure, you can see how each successive state of the activity determines which callback methods a fragment may receive. For example, when the activity has received its onCreate() callback, a fragment in the activity receives no more than the onActivityCreated() callback.

 

片段的生命周期流程,正如它被其宿主活动所影响那样,在图3中描述。在这张图中,你可以看到活动的每个连续的状态决定一个片段可以接收哪些回调方法。例如,当活动接收其onCreate()回调时,活动中的一个片段正好接收到onActivityCreated()回调。

 

Once the activity reaches the resumed state, you can freely add and remove fragments to the activity. Thus, only while the activity is in the resumed state can the lifecycle of a fragment change independently.

 

一旦活动到达被恢复状态,你可以从活动中自由地添加和移除片段。因此,仅当活动正在被恢复状态时,片段的生命周期才可以独立地改变。

 

However, when the activity leaves the resumed state, the fragment again is pushed through its lifecycle by the activity.

 

然而,当活动离开被恢复的状态,片段再一次被活动推动执行它的生命周期。

 

-------------------------------

 

Example

 

示例

 

To bring everything discussed in this document together, here's an example of an activity using two fragments to create a two-pane layout. The activity below includes one fragment to show a list of Shakespeare play titles and another to show a summary of the play when selected from the list. It also demonstrates how to provide different configurations of the fragments, based on the screen configuration.

 

为了把本文讨论的所有东西联系起来,这里有一个例子,一个使用两个片段创建双窗格布局的活动。下面的活动包含一个片段用于显示莎士比亚戏剧标题的列表,以及另一个片段用于显示在列表中选中戏剧的概要。它还演示了如何基于屏幕配置,提供不同片段配置。

 

-------------------------------

 

Note: The complete source code for this activity is available in FragmentLayout.java.

 

注意:此活动的完整源代码在FragmentLayout.java中可用。

 

-------------------------------

 

The main activity applies a layout in the usual way, during onCreate():

 

主活动以通常的方式应用布局,在onCreate()期间:

 

-------------------------------

 

@Override

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

 

    setContentView(R.layout.fragment_layout);

}

 

-------------------------------

 

The layout applied is fragment_layout.xml:

 

应用的布局是fragment_layout.xml:

 

-------------------------------

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="horizontal"

    android:layout_width="match_parent" android:layout_height="match_parent">

 

    <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"

            android:id="@+id/titles" android:layout_weight="1"

            android:layout_width="0px" android:layout_height="match_parent" />

 

    <FrameLayout android:id="@+id/details" android:layout_weight="1"

            android:layout_width="0px" android:layout_height="match_parent"

            android:background="?android:attr/detailsElementBackground" />

 

</LinearLayout>

 

-------------------------------

 

Using this layout, the system instantiates the TitlesFragment (which lists the play titles) as soon as the activity loads the layout, while the FrameLayout (where the fragment for showing the play summary will go) consumes space on the right side of the screen, but remains empty at first. As you'll see below, it's not until the user selects an item from the list that a fragment is placed into the FrameLayout.

 

使用这个布局,当活动加载布局时系统会实例化TitlesFragment(它列出戏剧标题),但是当FrameLayout(用于显示戏剧概要的片段将要出现的地方)占用了屏幕的右侧空间时,会马上保持空白。正如你在下面看到的,直至用户选择列表中的一项,把片段放进FrameLayout内,才会这样。

 

However, not all screen configurations are wide enough to show both the list of plays and the summary, side by side. So, the layout above is used only for the landscape screen configuration, by saving it at res/layout-land/fragment_layout.xml.

 

然而,不是所有屏幕配置都有足够的宽度并排显示戏剧列表和概要。所以,上面的布局只会用于宽屏配置,它保存在res/layout-land/fragment_layout.xml。

 

Thus, when the screen is in portrait orientation, the system applies the following layout, which is saved at res/layout/fragment_layout.xml:

 

同样,当屏幕在竖屏方向时,系统应用以下布局,它保存在res/layout/fragment_layout.xml。

 

-------------------------------

 

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent" android:layout_height="match_parent">

    <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"

            android:id="@+id/titles"

            android:layout_width="match_parent" android:layout_height="match_parent" />

</FrameLayout>

 

-------------------------------

 

This layout includes only TitlesFragment. This means that, when the device is in portrait orientation, only the list of play titles is visible. So, when the user clicks a list item in this configuration, the application will start a new activity to show the summary, instead of loading a second fragment.

 

这个布局只包含标题片段。这意味着,当设备在竖屏方向时,只有戏剧标题的列表是可见的。所以,当用户在这个配置下点击列表条目,应用程序将启动新的活动以显示概要,而非加载第二个片段。

 

Next, you can see how this is accomplished in the fragment classes. First is TitlesFragment, which shows the list of Shakespeare play titles. This fragment extends ListFragment and relies on it to handle most of the list view work.

 

接下来,你可以看到它是如何在片段类中实现。首先是TitlesFragment,它显示莎士比亚戏剧标题。这个片段继承自ListFragment,并且依赖它处理列表视图的大部分工作。

 

As you inspect this code, notice that there are two possible behaviors when the user clicks a list item: depending on which of the two layouts is active, it can either create and display a new fragment to show the details in the same activity (adding the fragment to the FrameLayout), or start a new activity (where the fragment can be shown).

 

当你查看此代码,注意当用户点击列表项时有两个可能的行为:依赖于两个布局中哪一个是激活的,它可以创建或显示一个新的片段以在相同的活动中显示细节(添加片段到FrameLayout),或启动新的活动(在那里可以显示片段)。

 

-------------------------------

 

public static class TitlesFragment extends ListFragment {

    boolean mDualPane;

    int mCurCheckPosition = 0;

 

    @Override

    public void onActivityCreated(Bundle savedInstanceState) {

        super.onActivityCreated(savedInstanceState);

 

        // Populate list with our static array of titles.

        // 生成带我们静态标题数组的列表。

        setListAdapter(new ArrayAdapter<String>(getActivity(),

                android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));

 

        // Check to see if we have a frame in which to embed the details

        // fragment directly in the containing UI.

        // 检查以查看我们是否拥有一个框架,在其包含的用户界面内直接嵌入了

        // 细节片段。

        View detailsFrame = getActivity().findViewById(R.id.details);

        mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;

 

        if (savedInstanceState != null) {

            // Restore last state for checked position.

            // 为勾选位置恢复最后状态

            mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);

        }

 

        if (mDualPane) {

            // In dual-pane mode, the list view highlights the selected item.

            // 在双窗格模式中,列表视图高亮了选中的条目

            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);

            // Make sure our UI is in the correct state.

            // 确保我们的用户界面在正确的状态。

            showDetails(mCurCheckPosition);

        }

    }

 

    @Override

    public void onSaveInstanceState(Bundle outState) {

        super.onSaveInstanceState(outState);

        outState.putInt("curChoice", mCurCheckPosition);

    }

 

    @Override

    public void onListItemClick(ListView l, View v, int position, long id) {

        showDetails(position);

    }

 

    /**

     * Helper function to show the details of a selected item, either by

     * displaying a fragment in-place in the current UI, or starting a

     * whole new activity in which it is displayed.

     *

     * 辅助函数,用于通过在当前用户界面的合适地方显示片段,

     * 或者通过启动整个新活动并在其中进行显示,来显示选中项的细节。

     */

    void showDetails(int index) {

        mCurCheckPosition = index;

 

        if (mDualPane) {

            // We can display everything in-place with fragments, so update

            // the list to highlight the selected item and show the data.

            // 我们可以用片段在适当的地方显示任何东西,这样更新

            // 列表可以使选中的条目高亮并显示数据。

            getListView().setItemChecked(index, true);

 

            // Check what fragment is currently shown, replace if needed.

            // 检查当前什么片段在显示,当需要时进行替换。

            DetailsFragment details = (DetailsFragment)

                    getFragmentManager().findFragmentById(R.id.details);

            if (details == null || details.getShownIndex() != index) {

                // Make new fragment to show this selection.

                // 构造新的片段显示这个选项。

                details = DetailsFragment.newInstance(index);

 

                // Execute a transaction, replacing any existing fragment

                // with this one inside the frame.

                // 执行事务,用框架内的这个片段替换任意存在的片段。

                FragmentTransaction ft = getFragmentManager().beginTransaction();

                ft.replace(R.id.details, details);

                ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);

                ft.commit();

            }

 

        } else {

            // Otherwise we need to launch a new activity to display

            // the dialog fragment with selected text.

            // 否则我们需要启动一个新活动,显示带选中文本的对话框片段

            Intent intent = new Intent();

            intent.setClass(getActivity(), DetailsActivity.class);

            intent.putExtra("index", index);

            startActivity(intent);

        }

    }

}

 

-------------------------------

 

The second fragment, DetailsFragment shows the play summary for the item selected from the list from TitlesFragment:

 

第二个片段,DetailsFragment显示TitlesFragment内列表的选中项的戏剧概要:

 

-------------------------------

 

public static class DetailsFragment extends Fragment {

    /**

     * Create a new instance of DetailsFragment, initialized to

     * show the text at 'index'.

     *

     * 创建DetailsFragment的新实例,初始化以在index上显示文本。

     */

    public static DetailsFragment newInstance(int index) {

        DetailsFragment f = new DetailsFragment();

 

        // Supply index input as an argument.

        // 提供index输入作为参数

        Bundle args = new Bundle();

        args.putInt("index", index);

        f.setArguments(args);

 

        return f;

    }

 

    public int getShownIndex() {

        return getArguments().getInt("index", 0);

    }

 

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container,

            Bundle savedInstanceState) {

        if (container == null) {

            // We have different layouts, and in one of them this

            // fragment's containing frame doesn't exist.  The fragment

            // may still be created from its saved state, but there is

            // no reason to try to create its view hierarchy because it

            // won't be displayed.  Note this is not needed -- we could

            // just run the code below, where we would create and return

            // the view hierarchy; it would just never be used.

            // 我们有不同的布局,而且在每个布局中这个片段都不存在。

            // 片段仍可以根据它已保存的状态来创建,但没理由尝试创建它的

            // 视图层次,因为它不会被显示。注意这是不需要的——我们仅需要

            // 运行以下代码,在那里我们创建和返回视图层次;它不会被使用。

            return null;

        }

 

        ScrollView scroller = new ScrollView(getActivity());

        TextView text = new TextView(getActivity());

        int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,

                4, getActivity().getResources().getDisplayMetrics());

        text.setPadding(padding, padding, padding, padding);

        scroller.addView(text);

        text.setText(Shakespeare.DIALOGUE[getShownIndex()]);

        return scroller;

    }

}

 

-------------------------------

 

Recall from the TitlesFragment class, that, if the user clicks a list item and the current layout does not include the R.id.details view (which is where the DetailsFragment belongs), then the application starts the DetailsActivity activity to display the content of the item.

 

如果用户点击列表条目并且当前布局不包含R.id.details视图(它从属于DetailsFragment),就会回调(注:重新调用)TitlesFragment类,然后应用程序启动DetailsActivity活动以显示条目的内容。

 

Here is the DetailsActivity, which simply embeds the DetailsFragment to display the selected play summary when the screen is in portrait orientation:

 

这是DetailsActivity,当屏幕在竖屏方向时,它简单地嵌入DetailsFragment以显示选中的戏剧概要:

 

-------------------------------

 

public static class DetailsActivity extends Activity {

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

 

        if (getResources().getConfiguration().orientation

                == Configuration.ORIENTATION_LANDSCAPE) {

            // If the screen is now in landscape mode, we can show the

            // dialog in-line with the list so we don't need this activity.

            // 如果屏幕现在是宽屏模式,我们可以在文中用列表显示对话框,

            // 所以我们不需要这个活动。

            finish();

            return;

        }

 

        if (savedInstanceState == null) {

            // During initial setup, plug in the details fragment.

            // 在初始化设置期间,插入细节片段。

            DetailsFragment details = new DetailsFragment();

            details.setArguments(getIntent().getExtras());

            getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();

        }

    }

}

 

-------------------------------

 

Notice that this activity finishes itself if the configuration is landscape, so that the main activity can take over and display the DetailsFragment alongside the TitlesFragment. This can happen if the user begins the DetailsActivity while in portrait orientation, but then rotates to landscape (which restarts the current activity).

 

注意,这个活动结束它自己如果配置是宽屏,致使主活动可以接管并在TitlesFragment旁边显示DetailsFragment。如果用户以竖屏方向启动DetailsActivity,但不久后旋转为宽屏(这样会重启当前活动),这可能会发生。

 

For more samples using fragments (and complete source files for this example), see the sample code available in ApiDemos (available for download from the Samples SDK component).

 

想获取更多使用片段的例子(以及这个例子的完整源文件),请参考在ApiDemos中可用的示例代码(可通过下载示例SDK组件获得)。

 

Except as noted, this content is licensed under Apache 2.0. For details and restrictions, see the Content License.

 

除特别说明外,本文在Apache 2.0下许可。细节和限制请参考内容许可证。

 

Android 4.0 r1 - 21 Oct 2011 2:44

 

Android 4.0 r1 - 29 Mar 2012 18:25

 

-------------------------------

patch:

1. Android 4.0 r1 - 29 Mar 2012 18:25

(1)

by pressing the BACK button.

->

by pressing the Back button.

 

(2)

there's not be enough room

->

there's not enough room

 

(3)

(simulating a BACK command by the user)

->

(simulating a Back command by the user)

 

(4)

by pressing the BACK key.

->

by pressing the Back button.

 

(5)

bring back the previous fragment by pressing the BACK key.

->

bring back the previous fragment by pressing the Back button.

 

(6)

and the BACK key will reverse them all together.

->

and the Back button will reverse them all together.

 

(7)

back to it with the BACK key,

->

back to it with the Back button,

 

-------------------------------

 

Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

 

(此页部分内容基于Android开源项目,以及使用根据创作公共2.5来源许可证中描述的条款进行修改)


你可能感兴趣的:(翻译)