fragment是Google在3.0版本中推出的新功能,现在已经加入到V4包中,如果要使用V4兼容包中的Fragment需要将Activity换成FragmentActivity,调用的getSupportFragmentManager获取FragmentManager而不是getFragmentManager。Fragment是Google大力推荐使用的一个功能,它和Activity功能其实差不多,不过比Activity更加的灵活和轻巧,Fragment寄存在Activity上面,他的生命周期直接受宿主Activity的影响,我们使用Fragment可以把它当做一个自定义视图一样来使用,使用好Fragment的前提是了解其生命周期,下面一张图来显示其与宿主Activity生命周期的关系:
当然上面的生命周期中我们不需要都重写,甚至你一个生命周期方法不写程序也可以正常运行。一般如果Fragment有视图的话我们需要重写onCreateView,更加需要你也可以重写其它的生命周期的方法。
与本节知识点相关的类主要有:FragmentManager、FragmentTransaction、Fragment这三个。这里我给大家提出来几个实用的类,都是Google帮我们分装好并且经常会使用到的类:DialogFragment、ListFragment、PreferenceFragment,第一个是用来创建Dialog的,第二个是一个含有ListView的Fragment,最后一个一般用来作为偏好方面的功能的设计,类似于手机里面的设置界面。下面就来给这三个类中的常用方法列出来。
FragmentManager:
beginTransaction():用来得到事务对象,后续对Fragment的添加删除等都是靠事务对象。
addOnBackStackChangedListener():给回退栈添加一个监听,回退栈中的Fragment数量变化都会调用这个监听。
findFragmentbyid():根据Fragment的id找到对应的Fragment;
findFragmentByTag():根据TAG找到对应的Fragment
popBackStack():将回退栈中的Fragment弹出也就是销毁,这个方法有很多个重载方法,可以指定一个Fragment弹出。
FragmentTransaction:
add():将一个Fragment添加到事务中,该方法有多个重载;
replace():将Fragment替换指定的容器控件,如果是动态创建一个Fragment经常使用这个方法。
addtoBackStack():将Fragment添加到回退栈中。
remove():移除一个Fragment对象。
hide():隐藏一个Fragment对象。
commit():提交本次事务,只要涉及到事务都会有这么一个方法,比如数据库中用到了事务也有这个方法。
show():跟hide对应使用。
Fragment:
setArguement():经常使用这个方法传递数据,对应的方法为getArgument();
我们用一个实例来演示Fragment的使用,实例只有一个Activity,而Activity布局文件中左右各一个Fragment,左边的Fragment中只有一个ListView,右边Fragment中只有一个ImageView,点击左边的ListView让右边的Fragment中的ImageView显示不同的图片。这里关键是左右Fragment交互的问题,解决这个问题我们有两种方式,一种是基于接口回调的方式,另一种我们可以是观察者模式,可以使用我们先前讲过的第三方EvnetBus,这里我们就使用接口回调的方式来解决,我们先来上效果图:
(这里ListView的线条不对的问题是模拟器的原因,真机运行不存在这个bug)
Fragment的使用有两种方式:
静态:直接在布局文件中声明Fragment。
动态:在布局文件中使用容器控件占位,然后使用前面说的replace方法替换掉。
因为第一种方式比较简单,这里的例子我们使用第二种方式。
首先来看Activity的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/containerB"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginRight="20dp"
android:layout_weight="1"
android:gravity="center"></RelativeLayout>
<FrameLayout
android:id="@+id/containerA"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"></FrameLayout>
</LinearLayout>
使用一个Relativelayout和一个framelayout作为占位控件。当然我们先要有2个Fragment,下面贴出两个Fragment的代码:
左边的Fragment:
public class BFragment extends Fragment {
private ListView listView;
private OnClickItemListener onClickItemListener;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
onClickItemListener = (OnClickItemListener) getActivity();
View view = inflater.inflate(R.layout.bfragment_layout, null);
listView = ((ListView) view.findViewById(R.id.bfragment_listView));
List<String> names = new ArrayList<>();
{
names.add("可爱");
names.add("活泼");
names.add("成熟");
names.add("高贵");
names.add("文静");
}
ArrayAdapter adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, names);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
onClickItemListener.clickedItem(position);
Toast.makeText(getActivity(), ((TextView) view).getText(), Toast.LENGTH_SHORT).show();
}
});
return view;
}
//回调接口用于传递数据
public interface OnClickItemListener {
void clickedItem(int position);
}
}
这里我们定义了一个接口OnClickItemListener用于和Activity通信。
右边的Fragment:
public class AFragment extends Fragment {
private View view;
private ImageView imageView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.afragment_layout, null);
imageView = (ImageView) view.findViewById(R.id.afragment_imgv);
imageView.setImageResource(R.drawable.girl);
return view;
}
@Override
public void onResume() {
super.onResume();
Bundle bundle = getArguments();
if (bundle != null) {
switch (bundle.getInt("position")) {
case 0:
imageView.setImageResource(R.drawable.loveliness);
break;
case 1:
imageView.setImageResource(R.drawable.lively);
break;
case 2:
imageView.setImageResource(R.drawable.ripe);
break;
case 3:
imageView.setImageResource(R.drawable.noble);
break;
case 4:
imageView.setImageResource(R.drawable.gentle);
break;
default:
imageView.setImageResource(R.drawable.girl);
}
}
}
}
这里代码很简单我就不多说了,下面重点是如何把这两个Fragment添加到Activity中和他们之间如何通信的。既然Activity是这两个Fragment的宿主,那么Activity和Fragment的通信自然是很简单的,既然Activity和Fragment通信很简单而且两个Fragment又是在同一个Activity中,那么他们之间的通信自然就很方便了,没错,我们就是使用Activity作为中转类似于手机通信中的基站的作用。前面一个Fragment已经提供了一个接口,我们只需要让Activity实现这个接口就可以了,至于把Fragment添加到Activity中的问题,我们前面已经提供了2个容器控件,这里就非常简单了,代码如下:
getFragmentManager().beginTransaction().replace(R.id.containerA, new AFragment()).commit();
getFragmentManager().beginTransaction().replace(R.id.containerB, new BFragment()).commit();
没错,简单的我都不想再和你提什么了!来看Activity的完整代码:
public class MainActivity extends Activity implements BFragment.OnClickItemListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getFragmentManager().beginTransaction().replace(R.id.containerA, new AFragment()).commit();
getFragmentManager().beginTransaction().replace(R.id.containerB, new BFragment()).commit();
}
@Override
public void clickedItem(int position) {
AFragment aFragment = new AFragment();
Bundle bundle = new Bundle();
bundle.putInt("position", position);
aFragment.setArguments(bundle);
getFragmentManager().beginTransaction().replace(R.id.containerA, aFragment).addToBackStack(null).commit();
}
}
扫描关注我的微信公众号:
是不是特别简单呢??我们只需要在重写的方法中动态的去创建右边的Fragment就可以把点击的位置传过去了,很微妙的一种方式,如果你对这个不太熟可以慢慢的体会其中的关系,这里我给大家说说大致的思路:左边的Fragment我们提供了一个接口,而里面又有一个属性是这个接口,属性指向Activity,当使用接口中的方法的时候系统会去找实现了这个接口的类,自然就找到了Activity了,也就是会执行Activity中重写的clickItem方法,因为这个方法在Activity中,我们自己可以在这个方法中动态的去创建又变的Fragment并且把点击的位置传给它。回调接口的时候刚开始我也不是很会,慢慢的不管他然后自己就回了,真是奇怪!!Fragment的知识大致就是这么多吧,最后送上demo给大家:点击打开链接