Fragment简介

来源:互联网 发布:朋友圈文案 知乎 编辑:程序博客网 时间:2024/05/16 07:45

Fragment(片段,碎片),正如其翻译那样,它在一个activity里面表示一个行为或者用户接口的一部分(碎片表示轻量级和灵活)。我们可以将不同的Fragments组合起来放到一个activity中,或者在不同的activity中重用一个fragment。你可以将一个fragment看成是一个activity中的一个片段,它有自己的生命周期(如何从创建到销毁),接受它自己的输入事件,并且可以在activity运行时动态的添加或者移除一个fragment(类似一个可以在不同的activity中重用的子activity)。

一个fragment必须总是绑定到一个activity中,并且被它的宿主activity的生命周期直接影响(fragment行为有点像自然界里面的寄生植物了,它有自己的生命周期,但是如果它的宿主植物挂掉的话,fragment自己也会挂掉)。比如,当一个activity暂停的时候,它里面所有的fragments也同样暂停,当activity销毁的时候,它里面所有的fragment同样也被销毁。然而,当一个活动正在运行(它处于resumed生命周期的时候),我们可以独立的操纵每个fragment执行注入添加和移除它们。当你执行一个fragment操作的时候,你可以将它添加到一个历史栈里面去,这个栈是由它的宿主维护。每一个栈里面的元素都是一个已经被执行过的fragment。通过这个堆栈我们可以通过按返回键来恢复之前的fragment。

当你将一个fragment作为activity的布局文件的一部分添加进去的时候,它就在activity的视图层次中的ViewGroup中,并且fragment可以定义自己的布局文件(layout)。可以通过在activity的layout中定义<fragment>元素来定义一个类中的fragment。或者在代码中将其添加到当前的ViewGroup(视图组合,或者称为视图元素组合)中。注意:一个fragment并不一定要求是activity布局文件的一部分,我们也可以使用一个没有自己UI的fragment,作为一个activity不可见的一部分。

这个文档将向你展示如何在你的应用中使用fragment,包括当fragment被添加到历史栈的时候如何管理他们自己的状态、如何与宿主或者宿主中的其他fragment进行通信、如何支持activity的action bar(类似窗口的标题栏,不过这个标题栏提供更多的操作,比如按钮跳转等,所以支持action的bar就叫action bar了)。

 

设计原理

Android在Android 3.0(API level 11)里面就介绍过fragments了,主要是为了在大屏幕设备上支持动态的和更灵活的UI设计(众所周知android 3.0只转为平板电脑设计,屏幕显示方面跟手机相比差异比较大)。为了适应大屏幕设备上面视图的转换所以设计了fragment。当我们将一个activity分割成了几个fragments,所以我们可以在运行时动态改变activity显示的内容,并且从activity管理的历史栈中回复前一次fragment。

以一个新闻应用为例,讲述Fragment如何起作用。我们可以使用一个左侧的fragment用来显示文章列表,另外一个右边的fragment显示文章内容,两个fragment都显示在一个activity中(屏幕大呗,所以可以适合显示两个)。这两个fragment都有独立的生命周期响应函数,并且独立处理各自的用户输入事件。这样对比之前的用两个activity来实现上的功能,我们只需要一个activity中包含显示不同内容的两个fragment就可以了。如图一所示:

                                                                       图一

我们必须将fragment设计成一个模块化的、可重用的活动组件。换句话说,因为每个fragment都定义有自己的布局,自己的生命周期行为,你可以也在很多活动中包含同一个fragment,所以必须设计一个可重用、并且避免在另外一个fragment中直接控制本fragment(2点,1、可重用;2、避免fragment间直接干扰)。模块化非常重要,因为这个特性使我们的应用在面对不同尺寸的屏幕时,允许我们改变fragment绑定方式。当我们设计一款手机和平板的应用时,我们可以通过在不同的布局中重用fragments,结合设备中的可用显示空间来最优化用户体验。例如,在手机中,可能需要将fragments分离成单个的UI(因为设备可用显示空间不足以显示一个以上的fragments)。

同样以新闻应用为例。在运行在平板电脑时,该应用可以将两个fragments绑定到Activity A中;当在手机中时,并没有多余的空间可以显示两个fragments,所以Activity A仅包含显示文章列表的fragment,当客户点击一篇文章的时候,会启动一个Activity B,这个activity中包含显示文章内容的fragment。这样,这款应用就可以通过使用fragment的方式,支持不同设备的尺寸了。




创建一个Fragment

为了创建一个fragment,我们必须先创建一个Fragment的子类(或者使用一个已存在的Fragment子类)。Fragment的代码类似于Activity,并且它包含的生命周期回调函数与activity也非常相似,比如,onCreate()、onStart()、onPause()、onStop().实际上如果我们想在一个应用上使用Fragment控件,只需要将活动的各个生命周期函数中的代码拷贝到Fragment对应的生命周期函数中即可。

通常我们必须实现下面的Fragment生命周期方法。

onCreate()

当创建一个Fragment时,系统就会调用这个方法。在这个方法的主体内,我们必须初始化一些必要的fragment参数。这样我们可以在fragment暂停、停止和重启的时候用得到。

onCreateView()

当Fragment第一次显示它自己时,系统就会调用这个函数。为了显示这个Fragment,必须在这个方法中返回一个视图,这个视图是作为fragment的布局文件根视图。当然,如果这个fragment没有提供UI的话,直接返回null就好了。

onPause()

当系统调用该方法时,就表示拥护离开这个fragment界面(然而并不总是表示该fragment被销毁了)。这个时候,我们一般会做一些拥护当前任务数据的存储备份工作(因为用户根本不会再进入这个界面了)。

大部分应用中的Fragment都应该实现至少上面3个方法,然而针对fragment的不同生命周期状态,还有其他几个回调函数需要实现。所有的生命周期函数会在后面讨论,见章节Handling the Fragment Lifecycle.

还有下面一些我们可以继承的Fragment子类,而不是从Fragment类继承:

DialogFragment

显示一个对话框。用这个类代替使用对话框创建器来创建对话框更好,因为我们可以将一个fragment对话框放入activity管理的Fragment堆栈,这样还允许用户返回一个取消显示的fragment。

ListFragment

显示一串用适配器管理的列表元素(比如SimpleCursorAdapter),类似于ListActivity。它提供几个管理列表视图的方法,比如onListItemClick()方法来应对点击事件。

PreferenceFragment

用列表的形式显示一些Preference对象,类似PreferenceActivity。这个在我们为自己的应用创建类似设置菜单的时非常有用。

  1. 添加一个UI

一个fragment通常用作activityUI的一部分,并且有自己的布局文件。当需要绘制fragment的时候,系统就会调用onCreateView()函数,所以当我们需要显示fragment的时候就必须实现这个函数。该函数返回一个view作为该fragment布局文件的根视图。

注意:如果我们使用的fragment是一个ListFragment的子类,那么这个函数默认返回ListView。

我们可以在这个函数里面返回一个在layout资源文件中定义的布局(通过inflate的方式,LayoutInflater对象)。

例如,下面的例子演示一个Fragment子类通过layout布局文件来载入自己的布局:

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

注意看inflater.inflate(R.layout.example_fragment, container, false);这一句。

上面传递的container变量是父类的ViewGroup,也就是fragment需要插入该视图内。savedInstanceState则存储恢复fragment的时候需要设置的变量(跟activity的对应概念相似)。inflate()方法需要三个变量,含义分别如下:

1. 需要实例化的资源id;

2. fragment需要在哪个视图组下面插入,第二个变量就是这个视图组;

3. 标识fragment的布局是否在inflate中需要绑定到该ViewGroup(本例中的false表示系统已经在container这个ViewGroup中插入了fragment的布局,如果再传一个true就会产生两个布局了)。

现在我们知道如何通过一个layout来创建一个fragment了。下一步我们就需要将这个fragment加入到我们的应用中了。

添加fragment到应用内

通常一个fragment构成宿主UI的一部分,而且这个部分在整个应用的构成中是可以灵活进行移除、添加等。有两种方法可以将一个fragment放入一个应用中:

在activity的布局文件中声明(Declare the fragment inside the activity's layout file.)

在这个例子中,可以在应用的布局文件中直接声明fragment标签,如下面的例子中该活动布局就声明了两个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>

android:name属性表示该fragment对应的Fragment的子类。

当系统创建应用的布局时,他会分别生成布局中声明的两个fragment,并且会调用每个fragment的onCreateView函数来生成每个fragment的布局。系统会将onCreateView函数返回的View插入到应用布局中声明fragment的地方。

Note: 每个fragment需要一个唯一的ID,这样当fragment需要重启的时候来恢复fragment。(也可以用该ID来执行其他的fragment事务,像移除fragment)有三种方式使fragment拥有唯一的ID:

  • 在声明fragment的时候添加android:id属性。
  • 添加一个android:tag属性,赋予唯一的字串。
  • 如果不想使用上面的两种方法,系统就使用包含该fragment的container的ID。

或者通过代码的方式将fragment添加到ViewGroup中(Or, programmatically add the fragment to an existing ViewGroup.)

在activity运行的任何时刻都可以添加fragment到应用布局中来。我们只需要获取到需要放置该fragment的ViewGroup即可(也就是上面说的container,fragment的容器)。

为了在活动中执行fragment事务(例如添加、删除、覆盖fragment操作),我们就必须使用FragmentTransaction中的API函数。我们可以通过下面的方式获取到一个FragmentTransaction实例:

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

我们就可以使用add方法将一个fragment添加到指定的ViewGroup中。例如:

ExampleFragment fragment = new ExampleFragment();fragmentTransaction.add(R.id.fragment_container, fragment);fragmentTransaction.commit();

add方法中,第一个变量就是我们想要将fragment放置的ViewGroup,在本例中通过一个资源ID来指定。第二个变量就是我们要添加的fragment了。只要我们对FragmentTransaction有了改变,最后必须使用commit方法提交这些影响。

0 0