Android ListFragment
Android是在Android 3.0(API level 11)开始引入Fragment的(为了兼容较低版本的设备使用支持库类)。可以把Fragment看成Activity中的模块,这个模块有自己的布局,有自己的生命周期(由托管activity调用其周期方法),单独处理自己的输入,在Activity运行的时候可以加载或者移除Fragment模块。
ListFragment是Fragment的子类,内置列表显示支持功能。ListFragment通过内置的ListView显示绑定在其上面的数据。下面就通过例子了解具体的用法:
1、模型层 Day类和DayLab类
通过DayLab对象的getDays()方法获取用来绑定的数据。
Day.java
package com.example.showdays;
import java.util.ArrayList;
public class Day {
private String mTitle;
public String getTitle() {
return mTitle;
}
public void setTitle(String mTitle) {
this.mTitle = mTitle;
}
}
DayLab.java
package com.example.showdays;
import java.util.ArrayList;
public class DayLab {
private ArrayList<Day> mDays;
public DayLab() {
mDays = new ArrayList<Day>();
for (int i = 1; i <= 10; i++) {
Day day = new Day();
day.setTitle("Title #" + i);
mDays.add(day);
}
}
public ArrayList<Day> getDays() {
return mDays;
}
}
2、创建DayListFragment类
继承ListFragment类。并给其内置的ListView设置Adapter
DayListFragment.java
package com.example.showdays;
import java.util.ArrayList;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.widget.ArrayAdapter;
public class DayListFragment extends ListFragment {
private ArrayList<Day> days;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DayLab dayLab = new DayLab();
this.days = dayLab.getDays();
ArrayAdapter<Day> adapter = new ArrayAdapter(getActivity(),
android.R.layout.simple_list_item_1, days);
// 第一个参数: Context对象,使用第二个参数的资源ID需要该Context对象
// 第二个参数: 资源ID,可定位ArrayAdapter用来创建View对象的布局,这里的实参是 Android SDK提供的预定义布局资源
// 第三个参数: 数据集
setListAdapter(adapter);// 给DayListFragment内置的ListView设置adapter
}
}
3、创建DayActivity类
继承FragmentActivity类。托管DayListFragment对象
其布局如下:
activity_day.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
在类中引用此布局文件,并将DayListFragment对象放置在id为fragmentContainer的FrameLayout容器视图中。
DayActivity.java
package com.example.showdays;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
public class DayActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_day);
FragmentManager fm = getSupportFragmentManager();
// 继承支持库类FragmentActivity获取FragmentManager对象的方法
// 若继承Activity使用getFragmentManager()
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) { // 查看fragment事务队列中是否存在此事物
fragment = new DayListFragment();
fm.beginTransaction().add(R.id.fragmentContainer, fragment)
.commit();
// 提交事务(资源ID作为唯一标识符且通知视图位置)
}
}
}
至此程序就可以正常运行了,运行效果如下图:
可以看到,已经呈现出列表形式,但是要显示的内容却不是我想要的。
那是因为 Android SDK提供的预定义布局资源(android.R.layout.simple_list_item_1)布局如下:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text1"
style="?android:attr/listItemFirstLineStyle"
android:paddingTop="2dip"
android:paddingBottom="3dip"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</TextView>
这样在ListView被实例化后与adapter会话时,ArrayAdapter<Day>.getView()方法会调用Day对象的toString()方法,然后将返回值传递给TextView。
所以覆盖Day对象toString()方法:
Day.java
package com.example.showdays;
import java.util.ArrayList;
public class Day {
private String mTitle;
public String getTitle() {
return mTitle;
}
public void setTitle(String mTitle) {
this.mTitle = mTitle;
}
@Override
public String toString() {
return mTitle;
}
}
此时再运行程序,运行效果如下图:
4、自定义列表项
上面使用的是Android SDK提供的预定义布局资源,直接把数据放置在TextView组件中来显示。
下面我就自定义一个列表项布局,将要显示的信息用Button组件来显示,布局如下:
my_list_item.xml
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false" >
</Button>
因为ListView更新视图的时候都要调用ArrayAdapter<Day>.getView()方法来获取View。所以要想把自己定义的列表项加入到ListView中,可以重写getView()方法,覆盖它并返回一个自己定义的View。做出改变如下:
DayListFragment.java
package com.example.showdays;
import java.util.ArrayList;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
public class DayListFragment extends ListFragment {
private ArrayList<Day> days;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DayLab dayLab = new DayLab();
this.days = dayLab.getDays();
DayAdapter adapter = new DayAdapter(days);
setListAdapter(adapter);
}
private class DayAdapter extends ArrayAdapter<Day> {
public DayAdapter(ArrayList<Day> days) {
super(getActivity(), 0, days);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) { // 此列表项是否存在,不存在则创建一个
convertView = getActivity().getLayoutInflater().inflate(
R.layout.my_list_item, null);
}
Day day = getItem(position); // 获取当前位置的Day对象
Button button = (Button) convertView.findViewById(R.id.button);
button.setText(day.toString());
return convertView;
}
}
}
最后运行一下,运行效果如下图: