https://developer.android.google.cn/guide/components/fragments.html
一、什么是Fragment
Fragment(碎片)就是小型的Activity,它是在Android3.0时出现的。Fragment是表现Activity中UI的一个行为或者一部分。
可以把fragment想象成activity的一个模块化区域,有它自己的生命周期,接收属于它自己的输入事件,并且可以在activity运行期间添加和删除(有点像一个可以在不同的activity中重用的“子Activity”)。
Fragment必须被嵌入到一个activity中。它们的生命周期直接受其宿主activity的生命周期影响。当一个activity正在运行时,就可以独立地操作每一个Fragment,比如添加或删除它们。
Fragment可以定义自己的布局、生命周期回调方法,因此可以将fragment重用到多个activity中,因此可以根据不同的屏幕尺寸或者使用场合改变fragment组合。
二、如何创建一个Fragment
1、为Fragment定义一个布局
2、定义类继承Fragment
3、重写类中的onCreateView()方法,返回一个View对象作为当前Fragm
ent的布局。
fragment第一次绘制它的用户界面的时候,系统会调用onCreateView()方法。为了绘制fragment的UI,此方法必须返回一个作为fragment布局的根的view。如果fragment不提供UI,可以返回null。
/**
* 定义类继承Fragment
*/
public class TitleFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//使用打气筒填充生成一个View对象,fragment_title是一个布局的根节点
View view = inflater.inflate(R.layout.fragment_title, null);
return view;
}
}
三、如何将Fragment添加到Activity
Activity必须在清单文件中进行声明,但是Fragment不需要,Fragment只需要在Activity的布局文件中声明就可以了。
<fragment
android:id="@+id/fmt_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.itheima.fragment.TitleFragment"
/>
注意:代码中的四个属性是必须的要给的,“android:name”属性:指定了在layout中实例化的Fragment类是哪个。当系统创建这个activity
layout时,它实例化每一个在layout中指定的Fragment,并调用它们的onCreateView()方法,来获取每一个Fragment的layout,系统将从Fragment返回的View直接插入到<fragment>元素所在的地方每一个fragment都需要一个唯一的标识,如果activity重启,系统可以用来恢
复Fragment,并且可以用id来捕获Fragment来处理事务,例如移除它。
有3种方法来为一个fragment提供一个ID,具体如下所示:
- 为android:id属性提供一个唯一ID;
- 为android:tag属性提供一个唯一字符串;
- 如果以上2个你都没有提供,系统将使用容器view的ID;
四、如何切换Fragment
要在activity中管理Fragment,需要使用FragmentManager可以通过调用activity的getFragmentManager()取得它的实例。
案例:点击不同的按钮切换到不同的Fragment进行显示。具体实现步骤:
1、设置布局文件:添加三个按钮用于切换Fragment,并在按钮下方
添加一个FrameLayout用来替换成响应的Fragment。
2、创建三个Fragment,SportsFragment、NewsFragment、GameFragment。
public class SportsFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 使用打气筒生成一个View对象
View view = inflater.inflate(R.layout.fragment_sports, null);
return view;
}
}
其余两个Fragment跟SportsFragment代码一致,只是布局文件不同。
3、添加切换Fragment的逻辑,这个是新闻频道按钮的点击事件
public void news(View view){
//获取Fragment管理器对象
FragmentManager manager = getFragmentManager();
//开启事务
FragmentTransaction transaction = manager.beginTransaction();
//将FrameLayout控件替换成Fragment对象
transaction.replace(R.id.frame, new NewsFragment());
//提交事务
transaction.commit();
}
sports()方法、games()方法同上,因此不再给出代码清单。
4、运行程序,效果如下
Fragment的生命周期
Fragment的生命周期和activity生命周期很像,其生命周期方法如下所示。
- onAttach:绑定到activity
- onCreate:创建fragment
- onCreateView: 创建fragment的布局
- onActivityCreated: activity创建完成后
- onStart: 可见, 不可交互
- onResume: 可见, 可交互
- onPause: 部分可见, 不可交互
- onStop:不可见
- onDestroyView: 销毁fragment的view对象
- onDestroy: fragment销毁了
- onDetach: 从activity解绑了
五、Fragment的向下兼容
Fragment是在Android3.0才推出的,若想在3.0的低版本下使用Fragment,则需要执行下面2步:
1、把所有Fragment和FragmentManager改成support-v4包下的类
2、把Activity的继承改为FragmentActivity(support-v4包下的)
六、Fragment之间的通信案例
案例:创建一个用于显示选项卡的Fragment和一个用于显示内容的Fragment,当选项卡切换时,使内容的Fragment信息跟着一起切换。具体实现步骤如下所示:
1、先创建选项卡Fragment和内容Fragment,并在activity_main.xml布
局文件中进行设置,其布局效果如下:
2、为选项卡Fragment创建布局文件,其布局效果如下:
3、添加内容区域Fragment的代码逻辑
public class ContentFragment extends Fragment {
private TextView tv_title;//标题
private ImageView iv_pic;//内容
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup
container, Bundle savedInstanceState) {
//使用打气筒填充布局
View view = inflater.inflate(R.layout.fragment_content, null);
//获取布局中的控件
tv_title = (TextView)view.findViewById(R.id.tv_title);
iv_pic = (ImageView) view.findViewById(R.id.iv_pic);
return view;
}
//定义一个方法,用于改变标题和图片
public void setTitleAndImage(String title, int picId) {
tv_title.setText(title);
iv_pic.setImageResource(picId);
}
}
4、添加选项卡区域Fragment的代码逻辑
public class TabFragment extends Fragment implements OnItemClickListener {
private String[] datas;
private int[] picIds;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup
container, Bundle savedInstanceState) {
//直接使用ListView作为布局,因此不需要布局文件
ListView listView = new ListView(getActivity());
//定义一些常量数据作为册数数据
datas = new String[]{"新闻", "体育", "财经", "社会", "娱乐", "国际"};
picIds = new int[]{R.drawable.a0, R.drawable.a1, R.drawable.a2, R.drawable.a3,
R.d rawable.a4, R.drawable.a5};
//设置点击事件
listView.setOnItemClickListener(this);
//声明一个ArrayAdapter对象
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_expandable_list_item_1, datas);
//给ListView设置Adapter
listView.setAdapter(adapter);
//返回视图
return listView;
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//获取当前的title和图片id
String title = datas[position];
int picId = picIds[position];
//获取Fragment管理器
FragmentManager manager = getFragmentManager();
//通过ID选择出ContentFragment对象
ContentFragment fragment = (ContentFragment) manager.findFragmentById(R.id.fragment_content);
//调用ContentFragment的方法,给ContentFragment传递参数,实现不同Fragment直接的通信
fragment.setTitleAndImage(title, picId);
}
}
Fragment与Activity如何交互?
这里我不再详细介绍那写比较常规的方式,例如静态变量,静态方法,持
久化,application全局变量,收发广播等等。
首先我们来介绍使用Handler来实现Fragment与Activity
的交互。第一步,我们需要在Activity中定义一个方法用来设置Handler对象。
public void setHandler(Handler handler) {
mHandler = handler;
}
第二步,在Fragment中的回调函数onAttach()中得到Fragment所在Activity,并调用setHandler方法,设置Handler。该Handler在Fragment中定义,用来接收消息与Fragment进行交互。
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mActivity = (MainActivity) activity;
mActivity.setHandler(mHandler);
}
public Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
text.setText((String) msg.obj);
break;
}
};
};
然后我们可以在Activity中发送消息给Fragment中的Hanlder进行交互。
public void inter(View view) {
Message msg = new Message();
msg.obj = edit.getText().toString();
msg.what = 1;
mHandler.sendMessage(msg);
}
Fragment回退栈实现
public class MainActivity extends FragmentActivity implements OnClickListener {
private FragmentA fragmentA;
private FragmentB fragmentB;
private FragmentC fragmentC;
private List<Fragment> fragmentsList = new ArrayList<Fragment>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btnA).setOnClickListener(this);
findViewById(R.id.btnB).setOnClickListener(this);
findViewById(R.id.btnC).setOnClickListener(this);
fragmentA = new FragmentA();
fragmentB = new FragmentB();
fragmentC = new FragmentC();
//将三个Fragment添加到帧布局中
/*
* 1. 获取FragmentManger
*/
FragmentManager fragmentManager = getSupportFragmentManager();
/*
* 2. 通过FragmentManager获取到事务管理器
*/
FragmentTransaction transaction = fragmentManager.beginTransaction();
/*
* 3. 将Fragment添加到帧布局中
*/
transaction.
add(R.id.fl, fragmentA, "FragmentA").
add(R.id.fl, fragmentB,"FragmentB").
add(R.id.fl, fragmentC,"FragmentC").
hide(fragmentB).
hide(fragmentC).
commit();
addToBackStack(fragmentA);
}
private void addToBackStack(Fragment fragment) {
if (fragmentsList.contains(fragment)) {
//先将老的对象移除
fragmentsList.remove(fragment);
//将Fragment添加到集合的最后
fragmentsList.add(fragment);
}else {
fragmentsList.add(fragment);
}
}
@Override
public void onBackPressed() {
// super.onBackPressed();
if (fragmentsList.size()>1) {
//移除最顶端的Fragment
fragmentsList.remove(fragmentsList.size()-1);
//将下一个Fragment给显示出来
showFragment(fragmentsList.get(fragmentsList.size()-1));
}else {
//如果当前栈中没有Fragment或者只有一个Fragment,直接退出Activity
finish();
}
}
private void showFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.hide(fragmentA).
hide(fragmentB).
hide(fragmentC).
show(fragment)
.commit();
}
@Override
public void onClick(View v) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.hide(fragmentA).hide(fragmentB).hide(fragmentC);
switch (v.getId()) {
case R.id.btnA:
transaction.show(fragmentA);
addToBackStack(fragmentA);
break;
case R.id.btnB:
transaction.show(fragmentB);
addToBackStack(fragmentB);
break;
case R.id.btnC:
transaction.show(fragmentC);
addToBackStack(fragmentC);
break;
default:
break;
}
//把当前事务添加到会退栈中
// transaction.addToBackStack(null);
transaction.commit();
}
}