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); } } } }
这里代码非常easy我就不多说了。以下重点是怎样把这两个Fragment加入到Activity中和他们之间怎样通信的。
既然Activity是这两个Fragment的宿主。那么Activity和Fragment的通信自然是非常easy的,既然Activity和Fragment通信非常easy并且两个Fragment又是在同一个Activity中。那么他们之间的通信自然就非常方便了,没错,我们就是使用Activity作为中转类似于手机通信中的基站的作用。前面一个Fragment已经提供了一个接口,我们仅仅须要让Activity实现这个接口就能够了。至于把Fragment加入到Activity中的问题,我们前面已经提供了2个容器控件,这里就非常easy了,代码例如以下:
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给大家:点击打开链接