Fragments(片段)

  一个fragment相当于activity中的一个行为或者用户界面的一部分。你可以在一个activity中组合很多的fragment去构建一个丰富多彩的UI界面而且不同的activity可以重复使用同一个fragment。你可以把fragment当作activity中的一个模块化的部分,它拥有自己的生命周期,可以接收自己的输入事件,也可以在activity运行时添加或删除fragment(有点像子activity,你可以在不同的地方重用)。

  一个fragment必须总是掐套在一个activity中而且fragment的生命周期直接被它寄主(activity)的生命周期所影响。例如,当activity暂停时,该activity中的所有fragment也会暂停,当activity被销毁时,所有的fragment也会被销毁。但是,当activity运行时(activity的状态是resumed时),你可以单独(independently)操作(manipulate)每一个fragment,比如移除或增加它们。当你处理一个fragment的事务(transaction)时,你也可以把它加入到一个back栈中,这个这个fragment就可以被activity所管理了--每一个back栈进入到activity代表着一个记录,表示fragment事务的发生。back栈允许用户改变fragment的事务(向后导航(navigate)),通过按back键。

  当你添加了一个fragment作为你activity布局的一部分时,它生存在一个activity统治下的ViewGroup中,并且fragment定义了它自己的布局文件。你可以为你activity的布局插入一个fragment通过在activity的布局文件中声明一个fragment。比如<fragment>标签。或者在你的工程内,通过代码的形式把fragment添加到一个已经存在的ViewGroup中。但是,fragment不是必须要是你activity布局的一部分。你也可以使用一个fragment不使用它拥有的UI,把它当作一个不存在的工人为你的activity服务。

  本篇文档告诉你怎么使用fragment在你的工程中,包括fragment怎么在加入activity的返回栈之后维持它自身的状态,分享activity的事件和其他activity中的fragments,贡献出activity的操作栏和更多。。

设计理念


Android在Android 3.0(API level 11)介绍了fragment,主要是为了支持在更大的屏幕上设计出更加动态更加可变的UI,比如说平板。因为平板的屏幕比手机大多了,有更多的空间去组合和交换UI的组件。fragment允许这样的设计,而且不需要你去管理复杂的view层次。通过把activity的布局分离成许多个fragments,你可以在程序运行的时候去修改(modify)fragments的外貌并且可以保持这些变化在back栈中,这样可以通过activity来管理。

举例来说,一个新的app可以使用一个fragment在屏幕的左侧显示一个文章的列表,也可以在屏幕的右侧也使用一个fragment来展示文章--这两个fragment出现在同一个activity中,并且,每一个fragment拥有自己一系列的生命周期回调函数并处理他们自己的input事件。通过这种设计,可以替代使用一个去显示文章列表,使用另一个activity去展示文章了。就像下图的设计(图1)

你可以把每个fragment设计成一个模块化的,可重复使用activity组件。这样说的原因是,每个fragment都拥有自己的layout并且自己的生命周期函数回调自身的行为。你可以把一个fragment放在多个activity中使用,所以应该设计成可重复使用的并且避免从一个fragment直接操作(manipulate)另一个fragment。这点尤其重要,因为模块化的fragment允许你为不同的屏幕大小改变你fragment的组合。当设计你的app既能适应平板也能使用手机时,你可以重复使用你的fragment在不同的布局文件上,在可以获得的屏幕上优化你的界面,提升用户体验。比如在手机上,你可以需要分离fragments去提供一个单窗格UI,去处理两个fragment无法同时出现在同一个activity上(图2)

继续拿做一个新的app做例子,一个app可以把两个fragment嵌入(embed)在同一个activity中(A),在平板大小的设备上运行。但在手机屏幕上,没有足够的空间去容纳两个fragment,所以无法把两个fragment放在同一个activity中。

创建一个Fragment


为了创建一个fragment,你必须创建一个Fragment的子类(或者一个存在的Fragment的子类)。Fragment类的代码看起来很像一个Activity,它包含和activity相似的回调函数,比如说onCreate(),onStart(),onPause()和onStop().实际上,如果你使用fragment去改造一个已经存在的app,你可以简单的把activity回调函数中的代码移植到对应的fragment的回调函数中。

通常来说,你应该至少实现以下几个生命周期函数:

1.onCreate()

  系统会在fragment创建时调用它,在你实现的这个方法里,你应该把fragment的组件初始化,目的是为了fragment在paused or stopped, then resumed时可以保留(retain)

2.onCreateView()

  当fragment第一次绘制它的用户界面时,系统会调用该方法。当你的UI绘制好后,你必须返回一个View对象,这个View对象是你的根layout。当你的fragment没有提供任何UI时,你可以返回null。

3.onPause()

   该方法是当用户有迹象离开你的fragment时(虽然这不意味着你的fragment正在被销毁)被调用。通常你应该在这个方法中提交当前用户所有需要提交的变化,因为用户可能不会再回来。

 

所有的app都应该为fragment实现至少这三个方法,但是还有其他的回调函数你应该使用去处理fragment多变的状态。关于这方面会在下面的处理fragment的生命周期中详细讲解。

 

除了继承Fragment实现外,还可以继承一下的类来实现

1.DialogFragment

  显示一个浮动(floating)的dialog。使用这个类去创建一个dialog是一个很好的选择去替代activity中的dialog。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.

2.ListFragment

  展示了一个被adapter管理的list,就像ListActivity。它提供了很多方法去管理一个list view,比如onListItemClick()回调函数去处理click事件。

3.PreferenceFragment  (偏好)

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

 

增加一个用户界面

fragment通常被当作用户界面的一部分并且为activity贡献出自己的layout。

为了给fragment提供一个layout,你必须实现onCreateView()方法,这个方法在fragment画自己的layout时被自动调用。你实现这个方法必须返回一个View对象作为fragment的root对象。

note:如果你的fragment是ListFragment的子类,那么onCreateView()方法默认返回的是ListView对象,所以你不必去实现它。

为了让onCreateView()返回一个layout,你可以inflate一个XML中定义的layout资源。为了帮助你这么做,onCreateView()方法提供了一个参数--LayoutInflater对象

eg:

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

 

container参数传递给onCreateView()的父ViewGroup(活动布局的),你的片段布局将被插入。

savedInstanceState参数是一个Bundle对象,如果片段被恢复,就为之前的fragment实例提供数据。(恢复状态讨论更多的在fragment的生命周期)。

inflate方法提供了三个参数

1.你想inflate的layout的资源id地方

2.ViewGroup是被inflate的layout文件的父布局。这个参数是很重要的,为的是使inflate的布局文件应用于根视图的布局上。

3.一个boolean值指示在inflate布局文件期间,是否应该把该layout附加到ViewGroup(第二个参数)中。(在这个例子中,我们写false是因为系统已经把被inflate的layout文件插入到ViewGroup对象中了--如果写true,就会创造一个冗余的view group在最终的布局中)

 

为Activity添加一个fragment

通常,一个fragment为主activity贡献出UI的一部分,嵌入在activity中,成为activity整个view层次的一部分。有两个方法可以为你activity的layout添加一个fragment:

1.在activity的layout文件中声明一个fragment

在这种情况下,你可以为你的fragment指定一个layout资源如果它是一个view。举例来说,下面是一个activity的layout文件,里面有两个fragment

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


<fragment>的android:name 属性用来指定某fragment类去实例化layout。当系统创建一个activity的layout,它实例化在在layout中指定的fragment并调用它的onCreateView()方法,去取回(return)每个fragment的layout。系统取回fragment返回的view直接代替<fragment>元素
笔记:每个fragment需要一个独一无二的标示符,为的是系统可以使用它去修复一个fragment如果activity被重启(你也可以用它来捕获 (capture)fragment执行的事务,比如删除)。有三种方法为fragment提供一个id
  • 提供一个android:id属性来生成一个独一无二的id
  • 提供一个android:tag属性来生成一个独一无二的string
  • 如果上述两个你都没做,系统会使用view容器的id

2.编程为已经存在的ViewGroup添加一个fragment

在任何时候,只要你的activity是运行中,你就可以为你activity布局添加fragments。你只需要在你要添加的地方指定一个ViewGroup。

为了使你的fragment在activity中可以做数据处理(如添加,移除,或者更换一个fragment),你必须使用FragmentTransaction。你可以在你的activity中获得FragmentTransation实例,就像这样:

  FragmentManager fragmentManager = getFragmentManager();

  FragmentTransaction fragmenttransaction = fragmentManager.beginTransaction();

接下来你可以通过add()方法添加一个fragment,指定fragment去添加并且试图将会被插入。例如:

  ExampleFragment fragment = new ExampleFragment();

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

  fragmentTrasaction.commit();

add()方法的第一个参数是给哪个ViewGroup添加fragment的资源id,第二个参数是添加哪个fragment。

一旦你使你的FragentTrasaction发生变化,你必须调用commit()方法。

 

管理fragment

通过事务的方式,用一个fragment替换另一个fragment。


Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);//必须写,不然无法把当前的fragment保存

transaction.commit();

在这个例子中,newFragment替换了容器中id为fragment_container的fragment。通过调用addToBackStack方法,被替换的事务被保存在back stack中,所以用户可以反转这个事务并且可以通过back按钮返回到之前的fragment(事务,统一反转)。

Communicating with the Activity




 

 

 

 

 

 

 

posted @ 2015-01-12 23:37  一路向前_Future  阅读(370)  评论(0)    收藏  举报