Fragment——01

Fragments

Fragment表现Activity中用户界面的一个行为或者是一部分。你可以在一个单独的activity上把多个fragment组合成为一个多区域的UI,并且可以在多个activity中再使用(复用性)。你可以认为fragment是activity的一个模块零件,它有自己的生命周期,接收它自己的输入事件,并且可以在activity运行时添加或者删除。(独立性

Fragment必须总是被嵌入到一个activity之中,一旦activity被暂停,它里面所有的fragment也被暂停,一旦activity被销毁,它里面所有的fragment也被销毁。然而,当activity正在运行时(处于resumed的生命周期状态),你可以单独的操控每个fragment,比如添加或者删除。当你执行这样一项事务时,可以将它添加到后台的一个中,这个栈由activity管理着——activity里面的每个后台栈内容实体是fragment发生过的一条事务记录。这个后台栈允许用户通过按BACK键回退一项fragment事务(往后导航)。

当你添加一个fragment作为某个activity布局的一部分时,它就存在于这个activity视图体系内部的ViewGroup之中,并且定义了它自己的视图布局。你可以通过在activity布局文件中声明fragment,用<fragment>元素把fragment插入到activity的布局中,或者是用应用程序源码将它添加到一个存在的ViewGroup中。然而,fragment并不是一个定要作为activity布局的一部分;fragment也可以为activity隐身工作。

设计原理

Android在3.0这个版本中引入了fragment的概念,主要是支持在大屏幕上更为动态和灵活的UI设计,比方说平板电脑。由于平板电脑的屏幕要比手持电话的大许多,这样就有更多的空间去组合和交换UI组件。有了fragment,你可以不必去管理视图体系的复杂变化。通过将activity的布局分割成若干个fragment,可以在运行时编辑activity的呈现,并且那些变化会被保存在由activity管理的后台栈里面。

  • 例如
    新闻应用程序将一个fragment放在左边显示文章列表,在右边用另一个fragment来显示一篇文章——两个fragment在同一个activity中并排着,并且每个fragment都有其自己的生命周期回调方法序列用以处理各自的用户输入事件。因此,用户可以在同一个activity中选择和阅读文章,而不是在一个activity中选择,在另一个activity中阅读,如图1所示。

应该将每一个fragment设计为模块化的和可复用化的activity组件。也就是说,你可以在多个activity中引用同一个fragment,因为fragment定义了它自己的布局,并且使用它本身生命周期回调的行为。这点尤为重要,因为它让你能够改变fragment组合以满足不同的屏幕尺寸。在设计同时支持平板电脑和手机的应用时,通过不同的布局配置可以复用fragments,基于可使用的屏幕空间优化用户体验。例如,在手机上,当同一个activity不能容纳更多的fragment时,可能需要通过分离fragments提供一个单区域的界面。

  • 例如
    还是以那个新闻应用程序为例——当程序运行在平板尺寸屏幕设备上时,可以在Activity A中嵌入两个fragment。但是,当运行在手机尺寸屏幕上,就没有足够的空间容纳两个fragment了,因此Activity A只能引用包含文章列表的fragment,在当用户选择一篇文章时,可以启动Activity B,它包含了用来阅读文章的第二个fragment。这样,应用程序通过以不同组合的复用fragments支持了平板电脑和手机
    在这里插入图片描述

一般情况下,你至少需要实现以下几个生命周期方法

  1. onCreate()

创建fragment时系统会调用此方法。在实现代码中,你可以初始化想要在fragment中保持的那些必要组件,当fragment处于暂停或者停止状态之后可重新启用它们。

  1. onCreateView()

第一次为fragment绘制用户界面时系统会调用此方法。为fragment绘制用户界面,这个函数必须要返回所绘出的fragment的根View。如果fragment没有用户界面可以返回空。

  1. onPause()

系统回调用该函数作为用户离开fragment的第一个预兆(尽管这并不总意味着fragment被销毁)。在当前用户会话结束之前,通常要在这里提交任何应该持久化的变化(因为用户可能不再返回)。

除了基类fragment,这里还有几个你可能会继承的子类:

  1. DialogFragment

显示一个浮动的对话框。使用这个类创建对话框是使用Activity类对话框帮助方法之外的另一个不错的选择,因为你可以把fragment对话框并入到由activity管理的fragments后台栈中,允许用户返回到一个已经摒弃的fragment。

  1. ListFragment

显示一个由适配器管理的条目列表(例如SimpleCursorAdapter),类似于ListActivity。并且提供了许多管理列表视图的函数,例如处理点击事件的onListItemClick()回调函数。

  1. PreferenceFragment

显示一个Preference对象的体系结构列表,类似于preferenceActivity。这在为应用程序创建“设置”activity时是很实用的。

添加用户界面

fragment常被用作activity用户界面的一部分,并且将本身的布局构建到activity中去。

为了给fragment提供一个布局,你必须实现onCreateView()回调函数,在绘制fragment布局时Android系统会调用它。实现这个函数时需要返回fragment所属的根View。
注意:如果你的fragment是ListFragment的子类,默认实现从onCreateView()返回一个ListView,所以你不需要实现它。
为了从onCreateView()返回一个布局,你可以从layout resource定义的XML文件inflate它。为了便于你这样做,onCreateView()提供一个LayoutInflater对象。

public static class ExampleFragment extends Fragment {
		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container,
								 Bundle savedInstanceState) {
			//要inflate的布局的资源ID
			//被inflate的布局的父ViewGroup
			//一个布尔值,表明在inflate期间被infalte的布局是否应该附上ViewGroup
			return inflater.inflate(R.layout.example_fragment, container, false);
		}
	}

将fragment添加到activity之中

在acitivity布局中添加fragment有两种方法:

  • 在activity的布局文件里声明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都需要一个唯一的标识(id),如果重启activity,系统可用来恢复fragment(并且可用来捕捉fragment的事务处理,例如移除)。为fragment提供ID有三种方法

  1. 用android:id属性提供一个唯一的标识。
  2. 用android:tag属性提供一个唯一的字符串。
  3. 如果上述两个属性都没有,系统会使用其容器视图(view)的ID。
  • 或者,通过编码将fragment添加到已存在的ViewGroup中
    应当使用FragmentTransaction的API来对activity中的fragment进行操作(例如添加,移除,或者替换fragment)。你可以像下面这样从Activity中取得FragmentTransaction的实例:
FragmentManager fragmentManager = getFragmentManager()
	FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

可以用add()函数添加fragment,并指定要添加的fragment以及要将其插入到哪个视图(view)之中:

ExampleFragment fragment = new ExampleFragment();
    //fragment被放置的ViewGroup,它由资源ID(resource ID)指定
    //要添加的fragment
	fragmentTransaction.add(R.id.fragment_container, fragment);
	fragmentTransaction.commit();

一旦通过FragmentTransaction 做了更改,都应当使用commit()使变化生效。

添加无界面的fragment

上面的例子是如何将fragment添加到activity中去,目的是提供一个用户界面。然而,也可以使用fragment为activity提供后台动作,却不呈现多余的用户界面。

想要添加没有界面的fragment ,可以使用add(Fragment, String)(为fragment提供一个唯一的字符串“tag”,而不是视图(view)ID)。这样添加了fragment,但是,因为还没有关联到activity布局中的视图(view) ,收不到onCreateView()的调用。所以不需要实现这个方法。

为无界面fragment提供字符串标签并不是专门针对无界面fragment的——也可以为有界面fragment提供字符串标签——但是对于无界面fragment,字符串标签是唯一识别它的方法。如果之后想从activity中取到fragment,需要使用findFragmentByTag()。

管理Fragments

想要管理activity中的fragment,可以使用FragmentManager。可以通过在activity中调用getFragmentManager()获得。

使用FragmentManager 可以做如下事情,包括:

  • 使用findFragmentById()(用于在activity布局中提供有界面的fragment)或者findFragmentByTag()获取activity中存在的fragment(用于有界面或者没有界面的fragment)。
  • 使用popBackStack()(模仿用户的BACK命令)从后台栈弹出fragment。
  • 使用addOnBackStackChangedListener()注册一个监听后台栈变化的监听器。

处理Fragment事务

在activity中使用fragment的一大特点是具有添加、删除、替换,和执行其它动作的能力,以响应用户的互动。提交给activity的每一系列变化被称为事务,并且可以用FragmentTransaction 中的APIs处理。你也可以将每一个事务保存在由activity管理的后台栈中,并且允许用户导航回退fragment变更(类似于activity的导航回退)。
获取FragmentTransaction实例,像这样:

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

下面的代码是如何使用另一个fragment代替一个fragment,并且将之前的状态保留在后台栈中:

//创建一个新的fragment和transaction
 Fragment newFragment = new ExampleFragment();
 FragmentTransaction transaction = getFragmentManager().beginTransaction();

 //newFragment替换了当前在布局容器中用R.id.fragment_container标识的所有的fragment
 //将事务添加到后台栈中,替代的事务被保存在后台栈中
 transaction.replace(R.id.fragment_container, newFragment);
 transaction.addToBackStack(null);
 //提交事务
 transaction.commit();

如果添加多个变更事务(例如另一个add()或者remove())并调用addToBackStack(),那么在调用commit()之前的所有应用的变更被作为一个单独的事务添加到后台栈中,并且BACK键可以将它们一起回退。

将变更添加到FragmentTransaction中的顺序注意以下两点:

  • 必须要在最后调用commit()
  • 如果你正将多个fragment添加到同一个容器中,那么添加顺序决定了它们在视图层次(view hierarchy)里显示的顺序。

在执行删除 fragment事务时,如果没有调用addToBackStack(),那么事务一提交fragment就会被销毁,而且用户也无法回退它。然而,当 移除一个fragment时,如果调用了addToBackStack(),那么之后fragment会被停止,如果用户回退,它将被恢复过来。

提示:对于每一个fragment事务,在提交之前通过调用setTransition()来应用一系列事务动作。
调用commit()并不立刻执行事务,相反,而是采取预约方式,一旦activity的界面线程(主线程)准备好便可运行起来。然而,如果有必要的话,你可以从界面线程调用executePendingTransations()立即执行由commit()提交的事务。但这样做,通常是没有必要的,除非其它线程的工作依赖与该项事务。

警告:只能在activity保存状态(当用户离开activity时)之前用commit()提交事务。如果你尝试在那时之后提交,会抛出一个异常。这是因为如果activity需要被恢复,提交后的状态会被丢失。对于这类丢失提交的情况,可使用commitAllowingStateLoss()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值