Android UI Fragment探索之进阶篇
一、ListFragment、ListView及ArrayAdapter
ListFragment的ListView将列表展示给用户,ListView是ViewGroup的子类,每一项都作为ListView的一个View子对象显示。那么,Veiw对象显示的视图从哪来呢?答案是adapter。
Adapter是一个控制器对象,从模型层获取数据,并将之提供给ListView显示,起到沟通桥梁的作用。Adapter负责:
- 创建必要的视图对象。
- 用模型层数据填充视图对象。
- 将准备好的视图对象返回给ListVeiw。
1 public class CrimeListFragment extends ListFragment 2 { 3 // method var 4 private ArrayList<Crime> mCrimes; 5 6 // method function 7 @Override 8 public void onCreate(Bundle savedInstanceState) 9 { 10 super.onCreate(savedInstanceState); 11 getActivity().setTitle(R.string.crime_title); 12 // data source 13 mCrimes = CrimeLab.get(getActivity()).getCrimes(); 14 15 // 创建adapter数据源 16 ArrayAdapter<Crime> adapter = new ArrayAdapter<Crime>(getActivity(), 17 android.R.layout.simple_list_item_1, mCrimes); 18 // 添加adapter数据源 19 setListAdapter(adapter); 20 } 21 22 }
PS:默认的ArrayAdapter<T>.getView(...)实现方法依赖于toString()方法。它首先生成布局的视图,然后找到指定位置的数据源对象,并对其调用toString()方法,最后,得到字符串信息并传递给UI控件。
二、使用自定义列表项
- 创建list_item_crime.xml文件:
1 <RelativeLayout 2 xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:tools="http://schemas.android.com/tools" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent"> 6 7 <CheckBox 8 android:id="@+id/list_item_checkbox" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:gravity="center" 12 android:layout_alignParentRight="true" 13 android:enabled="false" 14 android:padding="4dp"/> 15 16 <TextView 17 android:id="@+id/list_item_titletext" 18 android:layout_width="match_parent" 19 android:layout_height="wrap_content" 20 android:layout_toLeftOf="@+id/list_item_checkbox" 21 android:textStyle="bold" 22 android:paddingLeft="4dp" 23 android:paddingRight="4dp" 24 android:text="Crime title"/> 25 26 <TextView 27 android:id="@+id/list_item_datetext" 28 android:layout_width="match_parent" 29 android:layout_height="wrap_content" 30 android:layout_below="@+id/list_item_titletext" 31 android:layout_toLeftOf="@+id/list_item_checkbox" 32 android:paddingLeft="4dp" 33 android:paddingRight="4dp" 34 android:text="Crime date"/> 35 36 </RelativeLayout>
- 继承ArrayAdapter<T>类,重写获取getView(...)方法(继承这部分这里使用Java的内部类实现):
1 public class CrimeListFragment extends ListFragment 2 { 3 // method var 4 private ArrayList<Crime> mCrimes; 5 // click item tag 6 private static final String sTag = "CrimeListFragment"; 7 8 // method function 9 @Override 10 public void onCreate(Bundle savedInstanceState) 11 { 12 super.onCreate(savedInstanceState); 13 getActivity().setTitle(R.string.crime_title); 14 // data source 15 mCrimes = CrimeLab.get(getActivity()).getCrimes(); 16 17 // 创建adapter数据源 18 CrimeAdapter adapter = new CrimeAdapter(mCrimes); 19 // 添加adapter数据源 20 setListAdapter(adapter); 21 } 22 23 @Override 24 public void onListItemClick(ListView l, View v, int position, long id) 25 { 26 Crime c = (Crime)(getListAdapter()).getItem(position); 27 // Crime c = (CrimeAdapter)(getListAdapter().getItem(position)); 28 Log.d(sTag, c.getmTitle() + " was clicked."); 29 } 30 31 public class CrimeAdapter extends ArrayAdapter<Crime> 32 { 33 public CrimeAdapter(ArrayList<Crime> crimes) 34 { 35 super(getActivity(), 0, crimes); 36 } 37 38 @Override 39 public View getView(int position, View convertView, ViewGroup parent) 40 { 41 if (null == convertView) 42 { 43 convertView = getActivity().getLayoutInflater() 44 .inflate(R.layout.list_item_crime, null); 45 } 46 Crime c = getItem(position); 47 48 TextView title = (TextView)convertView.findViewById(R.id.list_item_titletext); 49 title.setText(c.getmTitle()); 50 TextView date = (TextView)convertView.findViewById(R.id.list_item_datetext); 51 date.setText(c.getmDate().toString()); 52 CheckBox solved = (CheckBox)convertView.findViewById(R.id.list_item_checkbox); 53 solved.setEnabled(c.getmSolved()); 54 55 return convertView; 56 } 57 } 58 59 }
PS: 这里有一点需要注意,由于列表项中,有CheckBox控件,CheckBox默认是可聚焦的,所以,点击列表项会被解读为切换CheckBox状态,自然也就不能触发onListItemClick(...)方法。解决方法为,将CheckBox默认聚焦设置false即可。
1 android:focusable="false"
三、向FrameLayout容器中,动态载入一个Layout布局对象
在fragment_main.xml文件中,FrameLayout标签中,嵌入一个FrameLayout标签:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 android:orientation="vertical" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent"> 7 8 <LinearLayout 9 android:layout_width="match_parent" 10 android:layout_height="wrap_content"> 11 12 <TextView 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:text="@string/main_name" 16 android:textColor="#000" 17 android:textSize="14sp"/> 18 19 <EditText 20 android:id="@+id/name" 21 android:layout_width="match_parent" 22 android:layout_height="wrap_content" 23 android:textSize="14sp" 24 android:textColor="#000"/> 25 26 </LinearLayout> 27 28 <LinearLayout 29 android:layout_width="match_parent" 30 android:layout_height="wrap_content"> 31 32 <TextView 33 android:layout_width="wrap_content" 34 android:layout_height="wrap_content" 35 android:text="@string/main_tel" 36 android:textColor="#000" 37 android:textSize="14sp"/> 38 39 <EditText 40 android:id="@+id/tel" 41 android:layout_width="match_parent" 42 android:layout_height="wrap_content" 43 android:textSize="14sp" 44 android:textColor="#000"/> 45 46 </LinearLayout> 47 48 <LinearLayout 49 android:layout_width="match_parent" 50 android:layout_height="wrap_content" 51 android:orientation="horizontal" 52 android:gravity="center"> 53 54 <Button 55 android:id="@+id/insert" 56 android:layout_width="wrap_content" 57 android:layout_height="wrap_content" 58 android:text="@string/main_insert" 59 android:textColor="#000"/> 60 61 <Button 62 android:id="@+id/query" 63 android:layout_width="wrap_content" 64 android:layout_height="wrap_content" 65 android:text="@string/main_query" 66 android:textColor="#000"/> 67 68 </LinearLayout> 69 70 <FrameLayout 71 android:id="@+id/user_list" 72 android:layout_width="match_parent" 73 android:layout_height="wrap_content"> 74 75 </FrameLayout> 76 77 </LinearLayout>
在代码中,为user_list动态载入一个ListFragment元素,(UserListFragment):
1 public class UserListFragment extends ListFragment 2 { 3 ...... 4 }
将UserListFragment嵌入FrameLayout布局标签中:
1 // 获取Fragment管理系统对象 2 FragmentManager fm = getFragmentManager(); 3 // 创建一个fragment对象 4 UserListFragment userListFragment = UserListFragment.newInstance(data); 5 // 通过Fragment管理器,将新创建的fragment对象添加到指定的布局容器中 6 fm.beginTransaction().add(R.id.user_list, userListFragment).commit();