转载自:http://blog.csdn.net/handsome_926/article/details/50736024
Fragment 用法总结(一)
Fragment有点类似View,一种增强版的View,不仅可以show、hide,而且有大量的生命周期方法,处理事件,更好的和Activity交互,在显示title和content的层级界面上有独特的优势,更好的兼容适应平板和手机。下面主要分三个部分讲解Fragment的创建及基本用法、生命周期和高级用法。
本文主要参考官方文档并加入自己整理的内容。
创建fragment
创建fragment必须要继承android.app.Fragment,还有下面几种除了Fragment基类的可扩展子类可以继承。
- DialogFragment
浮动对话框。使用DialogFragment创建对话框可有效地替代使用 Activity 类中的对话框帮助程序方法,因为可以将Fragment对话框纳入由 Activity 管理的Fragment返回栈,从而使用户能够返回清除的Fragment。 - ListFragment
显示由适配器(如 SimpleCursorAdapter)管理的一系列项目,类似于 ListActivity。它提供了几种管理列表视图的方法,如用于处理点击事件的 onListItemClick() 回调。 - PreferenceFragment
以列表形式显示 Preference 对象的层次结构,类似于 PreferenceActivity。这在为应用创建“设置” Activity 时很有用处。
如果使用Android3.0以下的版本,需要引入support.v4的包。
添加到Activity
使用布局
在 Activity 的布局文件内声明Fragment
可以将Fragment当作视图来为其指定布局属性。 例如:
- 1
- 2
- 3
- 4
- 5
- 6
<fragment>
中的 android:name
属性指定要在布局中实例化的 Fragment 类。
当系统创建此 Activity 布局时,会实例化在布局中指定的每个Fragment,并为每个Fragment调用 onCreateView()
方法,以检索每个Fragment的布局。系统会直接插入Fragment返回的 View
来替代 <fragment>
元素。
每个Fragment都需要一个唯一的标识符,重启 Activity 时,系统可以使用该标识符来恢复Fragment(也可以使用该标识符来捕获Fragment以执行某些事务,如将其删除)。 可以通过三种方式为Fragment提供 ID:
- 为 android:id 属性提供唯一 ID
- 为 android:tag 属性提供唯一字符串
- 如果未给以上两个属性提供值,系统会使用容器视图的 ID
动态添加
通过编程方式将Fragment添加到某个现有 ViewGroup
在 Activity 运行期间随时可以将Fragment添加到 Activity 布局中。只需指定将Fragment放入哪个 ViewGroup
。
要想在 Activity 中执行Fragment事务(如添加、删除或替换Fragment),必须使用 FragmentTransaction
中的 API。可以从 Activity
获取一个 FragmentTransaction
实例:
- 1
- 2
然后可以使用 add()
方法添加一个Fragment,指定要添加的Fragment以及将其插入哪个视图。例如:
- 1
- 2
- 3
传递到 add()
的第一个参数是 ViewGroup
,即应该放置Fragment的位置,由资源 ID 指定,第二个参数是要添加的Fragment。
一旦通过 FragmentTransaction
做出了更改,就必须调用 commit()
以使更改生效。
管理Fragment
要想管理 Activity 中的Fragment,需要使用 FragmentManager
。要想获取它,从 Activity
调用 getFragmentManager()
。
FragmentManager
可以执行的操作包括:
- 通过
findFragmentById()
(对于在 Activity 布局中提供 UI 的Fragment)或findFragmentByTag()
(对于提供或不提供 UI 的Fragment)获取 Activity 中存在的Fragment - 通过
popBackStack()
(模拟用户发出的 Back 命令)将Fragment从返回栈中弹出 - 通过
addOnBackStackChangedListener()
注册一个侦听返回栈变化的侦听器
如上文所说的,也可以使用 FragmentManager
打开一个 FragmentTransaction
,通过它来执行某些事务,如添加和删除Fragment。
执行Fragment事物
在 Activity 中使用Fragment的一大优点是,可以根据用户行为对Fragment执行添加、删除、替换以及其他操作。 commit
给 Activity 的每组更改都称为事务,FragmentTransaction 中的 API 用来执行事务。我们也可以将每个事务保存到由 Activity 管理的返回栈内,从而让用户能够回退Fragment更改(类似于回退 Activity)。
下面的代码表示如何从 FragmentManager 获取一个FragmentTransaction 实例:
- 1
- 2
事务都是原子性的,同时执行的一组更改。事物的方法都有:
add()
向Activity中添加一个Fragmentremove()
从Activity中移除一个Fragmentreplace()
使用另一个Fragment替换当前的hide()
隐藏当前的Fragment,不会调用生命周期回调方法show()
显示之前隐藏的Fragment,不会调用生命周期回调方法detach()
会将View从UI中移除,detach之后可以调用attach恢复视图。attach()
重建view视图,附加到UI上并显示。
这些方法为给定事务设置我们想要执行的所有更改。然后,要想将事务应用到 Activity,必须调用 commit()。
在调用 commit()
之前,我们可能会想到调用 addToBackStack()
,以便将事务添加到Fragment事务返回栈。 该返回栈由 Activity 管理,允许用户通过按“返回” 按钮返回上一Fragment状态。
例如,以下示例说明了如何将一个Fragment替换成另一个Fragment,以及如何在返回栈中保留先前状态:
- 1
- 2
在上例中,fragmentB
会替换目前在 R.id.content_main
ID 所标识的布局容器中的任何Fragment(如有)。通过调用 addToBackStack()
可将替换事务保存到返回栈,以便用户能够通过按“返回” 按钮撤消事务并回退到上一Fragment。上面用到replace方法,下一篇会讲到这些API对Fragment的生命周期的影响。
如果向事务添加了多个更改(如又一个 add() 或 remove()),并且调用了 addToBackStack(),则在调用 commit() 前应用的所有更改都将作为单一事务添加到返回栈,并且“返回” 按钮会将它们一并撤消。
向 FragmentTransaction 添加更改的顺序无关紧要,不过:
- 必须在最后调用
commit()
- 如果要向同一容器添加多个Fragment,则添加Fragment的顺序将决定它们在视图层次结构中的出现顺序
如果在执行删除Fragment的事务时没有调用 addToBackStack()
,则事务提交时该Fragment会被销毁,用户将无法回退到该Fragment。 如果在删除Fragment时调用了 addToBackStack()
,则系统会停止该Fragment,并在用户回退时将其恢复。addToBackStack()
方法可接受可选的字符串参数,来为事务指定独一无二的名称。除非你打算使用 FragmentManager.BackStackEntry API 执行高级 Fragment 操作,否则无需为addToBackStack()设置非空字符串参数。
提示:对于每个Fragment事务,都可以通过在提交前调用
setTransition()
来应用过渡动画。
调用 commit()
不会立即执行事务,而是在 Activity 的 UI 线程(“主”线程)可以执行该操作时再安排其在线程上运行。不过,如有必要,也可以从 UI 线程调用 executePendingTransactions()
以立即执行 commit()
提交的事务。通常不必这样做,除非其他线程中的作业依赖该事务。
注意:只能在 Activity保存Fragment状态(用户离开 Activity)之前使用
commit()
提交事务。如果试图在该时间点后提交,则会引发异常。 这是因为如需恢复 Activity,则提交后的状态可能会丢失。 对于丢失提交无关紧要的情况,请使用commitAllowingStateLoss()
。
与 Activity 通信
尽管 Fragment 是作为独立于 Activity 的对象实现,并且可在多个 Activity 内使用,但Fragment的给定实例会直接绑定到包含它的 Activity。
具体地说,Fragment可以通过 getActivity()
访问 Activity 实例,并轻松地执行在 Activity 布局中查找视图等任务。
- 1
同样地,Activity 也可以使用 findFragmentById() 或 findFragmentByTag(),通过从 FragmentManager 获取对 Fragment 的引用来调用Fragment中的方法。例如:
- 1
创建对 Activity 的事件回调
在某些情况下,可能需要通过Fragment与 Activity 共享事件。执行此操作的一个好方法是,在Fragment内定义一个回调接口,并要求宿主 Activity 实现它。 当 Activity 通过该接口收到回调时,可以根据需要与布局中的其他Fragment共享这些信息。
例如,一个 Activity 有两个个Fragment 分别是FragmentA、FragmentB,FragmentA随Activity创建时创建,点击A则切换到FragmentB,如图:
在Fragment A中声明ActionA接口:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
然后,该Fragment的宿主 Activity 会实现 ActionA 接口并实现 actionA(),并在方法内实现替换FragmentA为FragmentB:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
将来自FragmentA 的事件通知给保宿主 Activity,FragmentA 的 onAttach()
回调方法(系统在向 Activity 添加Fragment时调用的方法)会通过转换传递到 onAttach()
中的 Activity 来实例化 ActionA 接口的实例:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
实现时,actionA 成员会保留对 Activity 的 ActionA 实现的引用,以便FragmentA 点击事件发生时候可以通知Activity 替换当前Fragment。例如,点击FragmentA中的imageView,就会触发事件:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
其它交互方式
- Fragment操作Fragment
一般不建议这样做,除非有特别的需求,Activity担任的是Fragment间类似总线一样的角色,应当由它决定Fragment如何操作,在结构上如果由Fragment管理会变得混乱。 - 使用Activity的
newIntent()
Fragment通过启动宿主Activity(设置启动模式为singleTop),通过传入参数的方式判断显示哪个Fragment。
上面的Demo
上面讲了Fragment的一些常用方法,下一篇Fragment 用法总结(二)