ListFragment
ListFragment 是 Fragment 的子类,其内置列表显示支持功能。它的编写方法和普通的 Fragment 类似。示例:
1 2 3 4 5 6 7 8 9 10 11 public class CrimeListFragment extends ListFragment { private ArrayList<Crime> mCrimes; @Override public void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); getActivity().setTitle(R.string.crimes_title); mCrimes = CrimeLab.get(getActivity()).getCrimes(); } }
其中,mCrimes 是要被展示的对象列表。注意查看 getActivity()
方法。该 Fragment 便利方法不仅可以返回托管 Activity ,且允许 fragment 处理更多的 activity 相关事务。
ListView
ListView 是 ViewGroup 的子类,每一个列表项都是作为 ListView 的一个 View 子对象显示的。这些 View 子对象既可以是复杂的 View 对象,也可以是简单的 View 对象,这取决于我们对列表显示复杂度的需要。
ListView 是从 adapter 申请视图对象的。adapter 是一个控制器对象,从模型层获取数据,并将之提供给 ListView 显示,起到了沟通桥梁的作用。
adapter 负责:
创建必要的视图对象;
用模型层数据填充视图对象;
将准备好的视图对象返回给 ListView 。
adapter 是实现 Adapter 接口的类实例。例如,ArrayAdapter 类知道如何处理数组(或 ArrayList)中的 T 类型对象。下图展示了 ArrayAdapter 类的继承图谱。继承图谱的每一个节点都提供了该层级类或接口的专业化形式。
ListView 需要显示视图对象时,会与其 adapter 展开会话沟通。下图展示了 ListView 向其数组 adapter 启动会话的例子。
创建 Adapter
下面以 ArrayAdapter 为例学习如何编写 adapter 。
首先,使用以下构造方法创建一个默认的 ArrayAdapter 类实现:
1 public ArrayAdapter (Context context, int textViewResourceId, T[] objects)
数组 adapter 构造方法的第一个参数是一个 Context 对象,使用第二个参数的资源 ID 需要该 Context 对象。资源 ID 可定位 ArrayAdapter 用来创建 View 对象的布局。第三个参数是数据集(要展示的数组对象)。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Override public void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); getActivity().setTitle(R.string.crimes_title); mCrimes = CrimeLab.get(getActivity()).getCrimes(); ArrayAdapter<Crime> adapter = new ArrayAdapter<Crime>(getActivity(), android.R.layout.simple_list_item_1, mCrimes); setListAdapter(adapter); }
另外要注意的一点是,ArrayAdapter<T>.getView(...)
实现方法依赖于 toString()
方法。因此,一定要确保被显示的对象提供了合理的 toString()
方法。例如,可以覆盖该被显示对象的 toString()
使其返回该对象的标题属性:
1 2 3 4 @Override public String toString () { return mTitle; }
响应列表项的点击事件
要响应用户对列表项的点击事件,可覆盖 ListFragment 类的另一便利方法:
1 public void onListItemClick (ListView l, View v, int position, long id)
示例:
1 2 3 4 5 6 7 8 9 10 11 public class CrimeListFragment extends ListFragment { private static final String TAG = "CrimeListFragment" ; ... @Override public void onListItemClick (ListView l, View v, int position, long id) { Crime c = (Crime)(getListAdapter()).getItem(position); Log.d(TAG, c.getTitle() + "was clicked" ); } }
定制列表项
定制列表项需完成以下任务:
创建定义列表项视图的 XML 布局文件;
创建 ArrayAdapter 的子类,用来创建、填充并返回定义在新布局中的视图。
定制布局用来显示特定 Crime 对象信息的列表项。列表项要显示的数据信息必须使用 Crime 类的 getter 方法才能获取,因此,我们需创建一个知道如何与 Crime 对象交互的 adapter 。例如可以在 ListFragment 类中创建一个 ArrayAdapter 的子类作为内部类。
1 2 3 4 5 private class CrimeAdapter extends ArrayAdapter <Crime > { public CrimeAdapter (ArrayList<Crime> crimes) { super (getActivity(), 0 , crimes); } }
创建并返回定制列表项是在以下 ArrayAdapter 方法里实现的:
1 public View getView (int position, View convertView, ViewGroup parent)
convertView 参数是一个已存在的列表项,adapter 可重新配置并返回它,因此我们无需再创建全新的视图对象。复用视图对象可避免反复创建、销毁同一类对象的开销,应用性能因此得到了提高。ListView 一次性需显示大量列表项,因此,没有理由产生大量暂不使用的视图对象来耗尽宝贵的内存资源。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 private class CrimeAdapter extends ArrayAdapter <Crime > { public CrimeAdapter (ArrayList<Crime> crimes) { super (getActivity(), 0 , crimes); } @Override public View getView (int position, View convertView, ViewGroup parent) { if (convertView == null ) { convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_crime, null ); } Crime c = getItem(position); TextView titleTextView = (TextView)convertView.findViewById(R.id.crime_list_item_titleTextView); titleTextView.setText(c.getTitle()); TextView dateTextView = (TextView)convertView.findViewById(R.id.crime_list_item_dateTextView); dateTextView.setText(c.getDate().toString()); CheckBox solvedCheckBox = (CheckBox)convertView.findViewById(R.id.crime_list_item_solvedCheckBox); solvedCheckBox.setChecked(c.isSovled()); return convertView; } }
最后需要在 ListFragment 类绑定定制的 adapter ,更新 onCreate()
和 onListItemClick()
方法以实现 CrimeAdapter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Override public void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); getActivity().setTitle(R.string.crimes_title); mCrimes = CrimeLab.get(getActivity()).getCrimes(); CrimeAdapter adapter = new CrimeAdapter(mCrimes); setListAdapter(adapter); } @Override public void onListItemClick (ListView l, View v, int position, long id) { Crime c = ((CrimeAdapter)(getListAdapter()).getItem(position); Log.d(TAG, c.getTitle() + "was clicked" ); }