Android API Guides---Fragments

一个Fragment代表了一个行为或在活动用户界面的一部分。您可以在一个单一的活动结合多个片段来构建一个多窗格界面和重用在多个活动片段​​。你可以把一个片段作为一个活动,它有自己的生命周期的一个模块化部分,接收其自己的输入事件,并可以添加或活动运行时卸下(有点像一个“子活动”,你可以在不同的活动重用)。


片段必须始终嵌入的活动和片段的生命周期中是直接受主机活动的生命周期。例如,当活动暂停,所以是在它的所有片段,并且当活动被破坏,因此是所有片段。然而,活动运行(这是在恢复生命周期状态),同时,可以独立操作每个片段,如添加或删除它们。当您执行这样一个片段的交易,你也可以将其添加至由该活动的每一个后退堆栈中的活动条目管理是发生的片段交易的记录一回堆栈。背面堆栈允许用户翻转片段交易(导航向后),按后退按钮。


当您添加一个片段作为你的活动布局的一部分,它生活在该活动的视图层次结构内的ViewGroup和碎片定义了自己的看法布局。您可以通过它添加到现有的ViewGroup宣布在活动的布局文件片段,作为<片段>元素,或从应用程序代码中插入片段插入你的活动布局。然而,要在活动布局的一部分的片段不是必需的;你也可以使用一个片段,没有它自己的UI作为活动的一种无形的工人。


本文介绍了如何构建你的应用程序中使用的片段,包括什么时候加入到活动的回栈片段如何能保持自己的状态,在该活动的活动和其他片段共享活动,有助于活动的行动吧,和更多。


设计理念


在Android的Andr​​oid 3.0的(API级别11)介绍片段,主要是为了支持在大屏幕上更具活力和灵活的用户界面设计,如平板电脑。由于平板电脑的屏幕比手机大很多,有更多的空间来结合和交换UI组件。片段允许这样的设计,而不需要你来管理视图层次结构复杂的变化。通过将一个活动成片段的布局,成为您能够修改活动的外观在运行时和保存一回堆栈是由活动管理的这些变化。


例如,一个消息应用程序可以使用一个片段来显示的左侧和另一片段的文章的列表来显示上的一篇文章右两个片段出现在一个活动,并排,并且每个片段具有其自己的一组的生命周期的回调方法和处理自己的用户输入事件。因而,代替使用一个活动选择的物品和另一个活动阅读文章中,用户可以选择一篇文章,并且在同一活动内读这一切,如在图1中的片剂布局示出。


你应该设计每个片段作为一个模块化和可重用活性组分。也就是说,因为每个片段定义自己的布局,并有自己的生命周期回调自身的行为,您可以在多种活动一个片段,所以你应该设计重用,并避免直接从另一个片段操纵一个片段。这一点尤其重要,因为模块化的片段让你改变你的片段组合为不同的屏幕尺寸。在设计应用程序以支持平板电脑和手机,你可以重用片段不同的布局结构优化基础上,可用的屏幕空间的用户体验。例如,在手机上,可能有必要以分离的片段,以提供一个单窗格UI时多于一个不能在同一活动内适合。

Android API Guides---Fragments_第1张图片


图1如何通过片段定义的两个用户界面模块可以组合成用于片剂设计一种活性,但对于一个手机设计分开的一个例子。


例如,继续与新闻应用程序的例子,该应用程序可以嵌入活动一两个片段,一个平板大小的设备上运行时。然而,手持机尺寸屏幕上,没有足够的空间,这两个片段,活动A仅包括的物品列表中的片段,并且当用户选择的物品,它启动活动B,其中包括第二个片段来读取这篇文章。因此,应用程序通过以不同的组合重用片段,如在图1中所示支持片剂和手机。


有关设计为不同的屏幕配置不同的片段组合应用程序的更多信息,请参阅该向导支持片和手机。


创建Fragment




图2(同时其活动正在运行)的片段的生命周期。

Android API Guides---Fragments_第2张图片



要创建一个Fragment,您必须创建Fragment的子类(或它的一个子类存在的)。该片段类有代码看起来很像一个活动。它包含类似于一个活动回调方法,如的onCreate(),在onStart(),的onPause(),和的onStop()。事实上,如果你把现有的Andr​​oid应用程序中使用的碎片,你可能只需移动从活动的回调方法的代码到你的片段各自的回调方法。


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


onCreate()
创建片段时,系统调用此。在您的实现,你应该初始化要当片段被暂停或停止保留片段的重要组成部分,然后重新开始。
onCreateView()
系统调用这个当它的时间段来绘制其用户界面的第一次。要绘制您片段的UI,你必须从这种方法那是你的片段布局的根返回一个视图。可以返回null如果片段不提供的UI。
onPause()
系统调用此方法如用户正在离开片段(尽管它并不总是意味着该片段被破坏)的第一指示。这通常是你应该犯应当超越当前用户会话被持久化(因为用户可能不会回来)的任何变化。
大多数应用程序应该实现至少每片段这三种方法,但也有你也应该用它来处理片段生命周期的不同阶段其他几个回调方法。所有生命周期回调方法中更详细地了解处理的片段生命周期的部分中讨论。


也有一些子类而不是基类的片段,你可能要扩展,:


DialogFragment
显示一个浮动对话框。使用这个类来创建一个对话框是一个很好的替代使用Activity类的对话框辅助方法,因为你可以将一个片段对话进入由活动管理的片段回栈,允许用户返回到被解雇片段。
ListFragment
显示由一个适配器(诸如SimpleCursorAdapter)管理的项目的列表,类似于ListActivity。它提供了一种用于管理列表视图几种方法,如onListItemClick()回调处理单击事件。
PreferenceFragment
显示偏好对象的层次结构作为列表,类似于PreferenceActivity。为应用程序创建一个“设置”活动时,这是非常有用的。
加入的用户接口


片段通常用作一个活动的用户界面的一部分,并有助于其自身的布局的活性。


为了提供一个片段的布局,你必须实现onCreateView()回调方法,当它的时间片段绘制它的布局,Android系统调用。此方法的实现必须返回一个观点,即是你的片段布局的根。


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


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


例如,下面是加载从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);
    }
}

创建布局


在上面的示例,R.layout.example_fragment是example_fragment.xml命名保存在应用程序资源布局资源的参考。有关如何在XML创建布局的信息,请参阅用户界面文档。
传递给onCreateView()的容器参数是其中的片段布局将被插入的父的ViewGroup(从活动的布局)。该savedInstanceState参数是提供数据关于该片段的一个实例,如果该片段正在恢复(复原状态被更多关于处理的片段生命周期的部分中讨论)一个包。


  inflate()方法有三个参数:


布局的资源ID要膨胀。
在的ViewGroup是布局膨胀的母公司。通过该容器是为了重要的系统中应用的布局参数充气布局的根视图,由其中它的将父视图指定。
一个布尔指示是否充气布局应膨胀期间被附接到的ViewGroup(第二个参数)。 (在这种情况下,这是假的,因为系统已经插入充气布局到容器传递真正会产生在最终布局冗余视图基。)
现在,你已经看到了如何创建提供了一个布局片段。接下来,你需要将片段添加到您的活动。


加入的片段到活动


通常,一个片段有助于用户界面的主机的活动,这被嵌入作为活动的整体图层次结构的一部分的部分。有两种方法可以将片段添加到活动布局:


声明活动的布局文件中的片段。
在这种情况下,可以就好像它是一个视图片段指定布局属性。例如,这是一个有两个片段活动的布局文件:
<?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>

Android的:在<Fragment > name属性指定片段类布局实例。
当系统创建这个活动的布局,它实例化布局指定的每个片段,并要求每一个onCreateView()方法,以检索每个片段的布局。该系统由插入片段直接代替<片段>元素返回的视图。
注:每个片段都需要一个唯一的标识符,该系统可以使用恢复片段,如果该活动将重新启动(并且你可以用它来捕捉片段进行交易,如删除)。有三种方式是提供一种用于片段的ID:
供应的android:id属性有唯一的ID。
供应机器人:标签属性带有一个唯一的字符串。
如果提供既不前两个的,本系统使用的容器视图的ID。
或者,该片段编程添加到现有的ViewGroup。
在当您的活动正在运行的任何时候,你可以添加片段您的活动布局。你只需要指定要放置片段的V​​iewGroup。
为了使片段交易你的活动(如添加,删除或替换的片段),您必须使用从FragmentTransaction的API。您可以从您的活动像这样得到FragmentTransaction的实例:
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

然后,您可以使用add()方法中添加一个片段,指定要添加的片段,并在其中插入该视图。例如:
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();

通过添加第一个参数()是其中的片段应放置,由资源ID指定的的ViewGroup,第二个参数是添加片段。
一旦你已经和你的FragmentTransaction变化,则必须调用commit()以使更改生效。
添加一个片段没有UI


上面的例子说明如何将片段以提供一个UI添加到您的活动。不过,你也可以使用一个片段,为活动背景的行为,而不提交补充UI。


要添加一个片段没有UI,使用add(片段,字符串)(提供一个唯一的字符串“标记”的片段,而不是一个视图ID)从活动中添加片段。这增加了该片段,但是,因为它不与活动布局视图相关联,它没有收到onCreateView()的调用。所以你不要需要实现的方法。


供给的字符串标签的片段是不严格用于非UI片段-还可以提供字符串标签到确有一个片段的UI,但如果该片段不具有用户界面,则该串标记是唯一的方式识别它。如果以后要获得该活动的片段,你需要使用findFragmentByTag()。


对于使用片段作为背景的​​工人,没有一个UI的例子活动,见FragmentRetainInstance.java样品,这是(通过Android SDK管理器中可用)包含在SDK样本中,位于您的系统上为<sdk_root> / APIDemos /app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java。


管理片段


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


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


获得存在于活性的片段,与findFragmentById()(用于在活动的布局提供的UI片段)或findFragmentByTag()(用于或不提供一个UI片段)。
流行的片段断背面堆栈,popBackStack()(用户模拟回命令)。
注册更改回堆栈的侦听器,具有addOnBackStackChangedListener()。
有关这些方法和其他的更多信息,请参阅FragmentManager类文档。


正如上一节所演示的,你也可以使用FragmentManager打开FragmentTransaction,它允许你进行交易,如添加和取出碎片。


执行片段交易


关于您的活动使用的片段一个很大的特点是添加,删除,替换,并与他们进行其他操作,响应用户交互的能力。每套你提交到活动的变化被​​称为一个事务,您可以在FragmentTransaction执行一个使用API​​。也可以每个事务保存于由活动管理的回栈,允许用户通过该片段的变化(类似于通过活动向后导航)向后导航。


你可以从这样的FragmentManager获得FragmentTransaction的实例:


FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

每个事务是一组要在同一时间进行的变化。您可以使用诸如加(设置所有你想给定事务执行的更改),删除(),并更换()。然后,向交易应用到活动,必须调用提交()。


在你调用commit(),但是,您可能要调用addToBackStack(),以交易添加到片段交易的背面栈。此回栈是由活动管理和使用户能够返回到前一片段的状态,通过按下返回按钮。


例如,这里是你如何可以与另一个替换一个片段,并在后面的堆栈保留以前的状态:


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

在这个例子中,newFragment替换任何片段(如果有的话)是目前在由R.id.fragment_container ID标识的布局容器。通过调用addToBackStack(),替换事务保存到后退堆栈,使用户可以反向交易,按后退按钮带回以前的片段。


如果添加多个变化到事务(如另一个附加()或remove())并调用addToBackStack(),则所有的更改你打电话之前提交()被添加到后退堆栈作为一个单一的交易和后退按钮将扭转它们放在一起。


在您添加变为FragmentTransaction的顺序并不重要,以下情况除外:


你必须调用commit()最后
如果您要添加多个片段到同一容器中,然后在其中添加的顺序决定了它们在视图层次结构的顺序
如果你不叫addToBackStack(),当您进行交易,消除片段,则该片段时提交事务破坏,用户无法导航回到它。然而,如果你调用addToBackStack()删除片段时,则该片段被停止,如果用户返回将会恢复。


提示:对于每一个片段的交易,你可以申请一个过渡动画,通过调用setTransition()在你提交之前。


在调用commit()并不立即执行交易。相反,它安排其到活动的UI线程(以下简称“主”线程)上只要线程能够这样做的运行。如果有必要,但是,你可以从你的UI线程调用executePendingTransactions()立即执行提交的事务提交()。这样做通常是没有必要,除非该交易在其他线程工作的依赖。


注意:您可以通过提交提交()只之前的节能活动的状态(当用户离开该活动)的交易。如果试图在该点之后提交,一个异常将被抛出。这是因为,在提交之后的状态可以如果活动需要恢复丢失。对于其中的好,你失去的承诺的情况下,使用commitAllowingStateLoss()。


与活动通信


虽然片段作为一个对象,它是独立于一个活动,可以在里面多项活动中使用实施,片段的给定实例直接连接到包含它的活动。


具体地,该片段可以访问与getActivity(活性实例)和容易执行的任务,如发现在活动的布局的图:


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

同样的,你的活动可以通过收购从FragmentManager的片段参考,使用findFragmentById()或findFragmentByTag()调用在片段的方法。例如:


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

创建事件回调到活动


在某些情况下,你可能需要一个片段与大家分享的活动事件。要做到这一点的一个好方法是定义片段内的回调接口,并要求该主机活动实现它。当活动通过接口接收回调,它可以与根据需要在布局其它片段的信息。


例如,如果一个新闻应用程序有一个活动,一个显示的文章(片段A)的列表两个片段,另一个显示,当一个列表项被选中 - 然后片段A必须告诉活动,这样的文章(片段B)它可以告诉片段B到显示文章。在这种情况下,OnArticleSelectedListener接口声明片段A内:


public static class FragmentA extends ListFragment {
    ...
    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }
    ...
}

然后,承载片段活动实现了OnArticleSelectedListener接口,并覆盖onArticleSelected()通知从片段A.事件的碎片B为确保主机活动实现了这个接口,片段A的onAttach()回调方法(系统调用时添加片段的活性)通过铸造传递到onAttach()中的活性实例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");
        }
    }
    ...
}

如果活动没有实现的接口,然后将片段抛出一个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 noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
        // Send the event and Uri to the host activity
        mListener.onArticleSelected(noteUri);
    }
    ...
}

传递给onListItemClick()id参数是被点击的项目,其中的活性(或其它片段)使用来从应用程序的ContentProvider的制品的行ID。


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


添加项目到操作栏


您的片段可以促进菜单项到活动的选项菜单(因而,操作栏)通过实现onCreateOptionsMenu()。为了让这个方法来接听电话,但是,你必须调用的onCreate期间setHasOptionsMenu()(),以表明该片段想将项目添加到选项菜单(否则,片段将不会接收到onCreateOptionsMenu()的调用)。


任何项目,你然后从片段添加到选项菜单被附加到现有的菜单项。当选择一个菜单项片段也接收回调onOptionsItemSelected()。


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


注意:虽然您的片段接收它增加了每个菜单项的上选择的项目回调,活性是第一,当用户选择一个菜单项以接收各自的回调。如果活动的实现上的项目选择的回调不处理所选择的项目,则该事件被传递到片段的回调。这是选项菜单和上下文菜单如此。


有关菜单的更多信息,请参阅菜单和操作栏开发人员指南。


处理片段生命周期




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


管理片段的生命周期是诸如管理活动的生命周期了很多。像的活性,片段可以在三种状态存在:


恢复
该片段是在运行活动可见。
已暂停
另一项活动是在前台和具有焦点,但在此生活片段的活性仍然可见(前台活动是部分透明或不覆盖整个屏幕)。
已停止
该片段是不可见的。任一主机活动已经停止或片段已从活动删除,但加入到背面栈。停止的片段是还活着(所有状态和成员信息被系统保留)。然而,它不再对用户可见,并且如果活动被杀死会被杀死。
另外像一个活动,您可以保留使用捆绑的片段,如果该活动的过程中被杀害的状态,以及需要在活动重新恢复片段的状态。您可以将片段的的onSaveInstanceState()回调过程中保存状态和过程中,可以的onCreate(),onCreateView()恢复它,或onActivityCreated()。有关保存状态的更多信息,请参见活动文档。


在生命周期的活性和片段之间的最显著差异是一个被如何存储在其各自的背部栈。活性被放置成是由该系统时,它的停止管理活动的背栈,由缺省值(这样,用户可以使用Back按钮导航回到它,如在任务和返回堆栈讨论)。然而,一个片段放入主机管理活动,只有当你明确要求例如通过交易,消除片段中调用addToBackStack()保存一回堆栈。


否则,管理片段的生命周期很相似管理活动的生命周期。因此,用于管理活动的生命周期相同的做法也适用于片段。你还需要了解,虽然是活动的生活是如何影响片段的生活。


注意:如果你需要你的片段中一个Context对象,你可以调用getActivity()。但是,要小心调用getActivity()只有当片段连接到一个活动。当该片段尚未连接,或者其生命周期,getActivity年底期间分离()将返回null。


与该活动的生命周期协调


在该片段住直接活动的生命周期影响片段的生命周期,使得每个生命周期回调用于在类似的回调为每个片段的活性的结果。例如,当活动接收的onPause(),在活动的每个片断接收的onPause()。


片段具有一些额外的生命周期回调,但是,处理以执行诸如生成动作和破坏片段的UI与活动独特相互作用。这些额外的回调方法有:


onAttach()
当该片段已用活性(该活性在这里通过)相关联的调用。
onCreateView()
调用,以创建与片段相关联的视图层次。
onActivityCreated()
当活动的onCreate()方法返回调用。
onDestroyView()
与片段相关联的视图层次被移除时调用。
onDetach()
当该片段被从活动解除关联调用。
一个片段的生命周期的流动,因为它是由它的主机活动的影响,是通过图3在该图中示出,可以看到活动的每个连续状态如何确定回调方法的片段可以接收。例如,当活动已收到其的onCreate()回调,在活性的片段接收不超过onActivityCreated()回调更多。


一旦活性达到续状态,可以自由添加和删除片段的活性。因此,只有当活动是在重新开始的状态可以在片段的生命周期独立地发生变化。


然而,当活动叶续状态,该片段再次通过其生命周期的活动推。





为了使本文件中一并讨论的一切,这里是用两个片段创建一个双窗格布局的活动的一个例子。下面的活动包括一个片段展现莎士比亚的播放列表中标题和从列表中选择当另一个展现该剧的摘要。它还演示了如何提供片段的不同的配置,是根据画面构成。


注:本次活动的完整源代码可在FragmentLayout.java。


主活动适用的onCreate()中以通常的方式布局,:


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.fragment_layout);
}

应用的布局是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>

采用这种布局,系统实例化TitlesFragment(其列出了播放标题)只要活动加载布局,而的FrameLayout(其中为示出播放摘要将去片段)在屏幕的右侧消耗空间,但一开始是空的。正如你将看到下面,它不是,直到用户选择从一个片段放入的FrameLayout列表中的项目。


然而,并非所有的屏幕配置的宽度足以同时显示由侧的戏剧的列表和摘要,侧。所以,上面的布局仅用于风景屏幕配置,通过在RES /布局脊/ fragment_layout.xml保存它。


因此,当屏幕处于纵向,系统将应用以下布局,这是保存在RES /布局/ 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>

这种布局只包括TitlesFragment。这意味着,当该装置处于直式定向,只播放标题的列表是可见的。这样,当用户在该构造点击列表项,应用程序将开始一个新的活动,以显示,而不是加载的第二片段的摘要。


接下来,你可以看到它是如何在片段类来完成的。首先是TitlesFragment,这显示了莎士比亚的戏剧标题列表。该片段扩展ListFragment并依靠它来处理大部分的列表视图的工作。


当你检查这些代码,请注意,有两种可能的行为,当用户点击列表项:这取决于两个布局被激活,它可以创建并显示一个新片段显示在同一个活动的详细信息(添加该片段到的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();
                if (index == 0) {
                    ft.replace(R.id.details, details);
                } else {
                    ft.replace(R.id.a_item, 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 fromTitlesFragment:

public static class DetailsFragment extends Fragment {
    /**
     * Create a new instance of DetailsFragment, initialized to
     * show the text at 'index'.
     */
    public static DetailsFragment newInstance(int index) {
        DetailsFragment f = new DetailsFragment();

        // Supply index input as an argument.
        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 theDetailsActivity activity to display the content of the item.

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

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();
        }
    }
}
The second fragment, DetailsFragment shows the play summary for the item selected from the list from TitlesFragment:


public static class DetailsFragment extends Fragment {
    /**
     * Create a new instance of DetailsFragment, initialized to
     * show the text at 'index'.
     */
    public static DetailsFragment newInstance(int index) {
        DetailsFragment f = new DetailsFragment();


        // Supply index input as an argument.
        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.


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


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

你可能感兴趣的:(android,api,sdk,阅读,谷歌)