1ListFragment
今天首先学习了一种非常常用的展示场景:列表展示。
昨天学习了使用Fragmet来代替activity进行设计,今天在托管单个fragment的基础上,掌握托管一个布局list。先看下效果:
因为Fragment列表需要使用ArrayList保存,而为了使Fragment对象受acrivity等生命周期影响, 创建如下单例类:
public class CrimeLab {
private ArrayList<Crime> mCrimes;
private static CrimeLab sCrimeLab;
private Context mAppContext;
private CrimeLab(Context context){
mAppContext=context;
mCrimes=new ArrayList<Crime>();
for(int i=0;i<100;i++){
Crime c =new Crime();
c.setTitle("Crime #"+i);
c.setSolved(i%2==0);
mCrimes.add(c);
}
}
public static CrimeLab get(Context c){
if(sCrimeLab==null){
sCrimeLab=new CrimeLab(c.getApplicationContext());
}
return sCrimeLab;
}
public ArrayList<Crime> getmCrimes(){
return mCrimes;
}
public Crime getCrime(UUID id){
for (Crime c: mCrimes){
if(c.getId().equals(id)){
return c;
}
}
return null;
}
}
同时,还要建立相应的fragment布局文件和类文件,实际上,存在专门支持list fragment的类:ListFragment。继承这个类即可,之后可使用其内置的listadapter。
为什么使用adapter呢? 因为我们的fragmentlab中新建了100个fragment对象,而我们不可能在一个页面中把他们全部显示出来,而是需要显示时才创建对象。adapter就是从模型层获得数据,并把它提供给ListView显示的桥梁。
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.isSolved());
return convertView;
}
}
实现自己定制Adapater的代码,之所以要实现自己的adapter,是因为在list的每一个条目我们定制了自己的布局。如代码中的list_item_crime.
这样就得到了list显示的fragment。
2ViewPager
ViewPager可以实现左右滑动屏幕切换查看不同列表项的功能。
ViewPager需要借助于Adapter才能够提供视图。 通过PagerAdapter的子类:FragmentStatePagerAdapter来处理两者间的配合问题。
这里需要实现两个方法,getCount()和getItem()。代码示例如下:
mViewPager.setAdapter(new FragmentStatePagerAdapter(fm) {
@Override
public int getCount(){
return mCrimes.size();
}
@Override
public Fragment getItem(int pos) {
Crime crime=mCrimes.get(pos);
return CrimeFragment.newInstance(crime.getId());
}
});
3 fragment数据传输
跟activity类似,fragment间也可以进行数据传输。而且fragment级的数据传输会使编程更加灵活。
试想如下场景: 在CrimeFragment中需要按键调出DatePickerFragment, 后者的初始化需要前者提供的数据。同时,DatePickerFragment的返回值也要作用于CrimeFragment。
需要做的事情有如下几步:
1)从CrimeFragment 初始化DatePickerFragment时, 将数据作为构造参数传入
2)DatePickerFragment构造时,将传入的值保存到argument
3)DatePickerFragment渲染时,取arguments中值
4)DatePickerFragment将值回传给CrimeFragment
为实现以上过程,首先要在DatePickerFragment 编写newInstance方法, 改方法可以在实例化DatePickerFragment时被调用并接受参数,同时在fragment create前准备好数据
public static DatePickerFragment newInstance(Date date){
Bundle args=new Bundle();
args.putSerializable(EXTRA_DATE,date);
DatePickerFragment fragment=new DatePickerFragment();
fragment.setArguments(args);
return fragment;
}
返回数据时,则覆盖onActivityResult方法。
交互过程如: