由于手机屏幕空间有限,能够一次性展现在屏幕上的内容并不多,当我们需要展现大量数据时,就可以通过ListView
来实现。
ListView
允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕。
应用场景:QQ聊天记录 、 微博消息
ListView的简单用法
简单实现ListView
创建一个Activity,在其视图中添加ListView
控件,并为其指定id
,长宽match_parent
。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/main_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
然后修改Activity中的代码:
public class MainActivity extends AppCompatActivity {
private ListView mListview;
private String[] data = {"item1","item2","item3","item4","item5","item6","item7","item8",
"item9,","item10","item11","item12","item13","item14","item15"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 绑定视图
mListview = (ListView) findViewById(R.id.main_2a'z'zlistview);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, data);
mListview.setAdapter(adapter);
}
}
效果如图所示:
自定义ListView
在上一节中,我们每一行填充的View是系统自带的资源android.R.layout.simple_list_item_1
,我们可以按住ctrl
加鼠标左键进入查看,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:minHeight="?android:attr/listPreferredItemHeightSmall" />
我们使用了系统提供的ArrayAdaper
作为ListView
的适配器,每行填充的视图就是上面的TextView
。然后把名为data的String类型数组依此填充进去。
关于Adapter
ListView控件是为了交互和展示数据用的,ListView也只承担交互和展示作用,而数据来自哪里和ListView无关。所以我们要使ListView起作用,我们需要一个ListView和一个数据源。
关键在于数据源,我们无法知道数据源是什么类型。它可能是数组,可能是对象集合,还可能是数据库表中查询出来的游标,如果ListView要为每一种数据源都进行适配操作的话,扩展性就会比较差。
Adapter适配器,它在ListView和数据源之间起到了一个桥梁的作用。ListView不直接和数据源打交道,而是借助Adapter作为桥梁来访问真正的数据源,
实际上我们可以自定义填充的View,我们也可以填充一个ViewGroup,例如:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/item_roadid"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="30sp"
android:gravity="center"/>
<TextView
android:id="@+id/item_redtime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="30sp"
android:gravity="center"/>
<TextView
android:id="@+id/item_greentime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="30sp"
android:gravity="center"/>
<TextView
android:id="@+id/item_yellowtime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="30sp"
android:gravity="center"/>
</LinearLayout>
这个ViewGroup由四个TextView组成。
在上节中我们直接使用了ArrayAdapter来作为适配器,ArrayAdapter继承自BaseAdapter,默认情况下,我们可以使用它的构造方法引用单个TextView的布局作为item。但如果布局较复杂,我们就需要加入TextView外层的布局的layout资源 ,即下图第四种用法。当TextView被引用之后,将会被填充传进来的数组对象的toString()
的值。
而我们需要更复杂的item,不仅仅是一个TextView,比如一个ImageView,或者一个Checkbox,亦或是一个Button。ArrayAdapter通过getView()方法获得每个item的View,所以我们需要重写ArrayAdapter的getView()方法来返回我们自己需要的View。我们通过继承来完成重写。
重写ArrayAdapter
因为我们不再使用String数组作为数据源,而是以对象list的形式作为数据源,所以我们先构建一个所需的对象。
我以交通灯为例,这个对象包含roadId
,redTime
,greenTime
,yellowTime
四个属性,然后创建了它的构造函数和一些getter/setter。
public class LightInfo {
private int roadId;
private int redTime;
private int greenTime;
private int yellowTime;
public LightInfo(int roadId, int redTime, int greenTime, int yellowTime) {
this.roadId = roadId;
this.redTime = redTime;
this.greenTime = greenTime;
this.yellowTime = yellowTime;
}
public int getRoadId() {
return roadId;
}
public void setRoadId(int roadId) {
this.roadId = roadId;
}
public int getRedTime() {
return redTime;
}
public void setRedTime(int redTime) {
this.redTime = redTime;
}
public int getGreenTime() {
return greenTime;
}
public void setGreenTime(int greenTime) {
this.greenTime = greenTime;
}
public int getYellowTime() {
return yellowTime;
}
public void setYellowTime(int yellowTime) {
this.yellowTime = yellowTime;
}
}
然后重写适配器:
public class LightInfoAdapter extends ArrayAdapter<LightInfo> {
private ArrayList list = new ArrayList();;
public LightInfoAdapter(@NonNull Context context, int resource, @NonNull List<LightInfo> objects) {
super(context, resource, objects);
}
@NonNull
@Override
public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.item_light_info, parent, false);
LightInfo lightInfo = getItem(position);
TextView roadId = (TextView) view.findViewById(R.id.item_roadid);
TextView redTime = (TextView) view.findViewById(R.id.item_redtime);
TextView greenTime = (TextView) view.findViewById(R.id.item_greentime);
TextView yellowTime = (TextView) view.findViewById(R.id.item_yellowtime);
roadId.setText(lightInfo.getRoadId()+"");
redTime.setText(lightInfo.getRedTime()+"");
greenTime.setText(lightInfo.getGreenTime()+"");
yellowTime.setText(lightInfo.getYellowTime()+"");
return view;
}
修改Activity中的代码
public class MainActivity extends AppCompatActivity {
private ListView mListview;
// 删除
//private String[] data = {"item1","item2","item3","item4","item5","item6","item7","item8","item9,","item10","item11","item12","item13","item14","item15"};
// 添加
private List<LightInfo> lightInfos = new ArrayList<>();;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 绑定视图
mListview = (ListView) findViewById(R.id.main_2a'z'zlistview);
// 删除
//ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, data);
// 添加
initData();
LightInfoAdapter adapter = new LightInfoAdapter(this,R.layout.item_light_info,lightInfos);
mListview.setAdapter(adapter);
}
// 添加死数据
private void initData() {
for (int i=0;i<4;i++) {
lightInfos.add(new LightInfo(i,i,i,i));
}
}
}
效果如图: