直接在任意布局里创建一个ListView就好了,但这个时候徒有其形,其中的条目内容是默认的,也无法互动。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
LinearLayout>
列表中的条目称之为item,这些item也有自己的布局,我们需要在res
->layout
文件夹中为其创建布局资源item_layout.xml
。其中为每个条目中的布局情况,这里演示比较简单,就用线性布局,组件就只有一个文本,设置其id为text
。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"/>
LinearLayout>
一般来说,item中的数据需要从别的渠道获取(比如联网),我们需要一个类来完成获取数据的操作,这个类就是Bean(我也不知道为啥要叫这个名字)。因为这里数据只有一个字符串,所以该类的成员变量只有一个String name
,然后使用快捷键Alt
+Insert
,选择Getter and Setter就可以快速补全代码。
package com.example.mylistview;
public class Bean {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
因为还没有学联网,这里先本地自己造一些放进条目里的字符串,主要是演示一下怎么使用Bean类。
先声明一个Bean类型的列表用来装数据:
private List<Bean> data = new ArrayList<>();
之后for循环,声明Bean类型的实例,设置其中的数据,然后存到列表里。
for(int i=0;i<100;++i){
Bean bean = new Bean();
bean.setName("ShadyPi"+i);
data.add(bean);
}
完成数据的获取之后,就需要将其放到ListView中,先通过findViewById
找到我们的ListView,然后通过一个adapter将数据填充进去。
ListView list = findViewById(R.id.list);
list.setAdapter(new MyAdapter(data, this));
MyAdapter类继承自安卓提供的BaseAdapter类,使用Alt
+Enter
就可以补全需要实现的四个方法的框架。分别是获取条目数量、获取Item、获取ItemID和获取View。
首先我们先把数据传入adapter中,这可以通过MyAdapter的构造方法来实现,分别传入data和context:
private List<Bean> data;
private Context context;
public MyAdapter(List<Bean> data, Context context) {
this.data = data;
this.context = context;
}
而自动补全的几个方法也需要略改一下,比如说获取条目数量,我们需要返回data列表的大小:
@Override
public int getCount() {
return data.size();
}
获取条目ID的时候我们直接返回i:
@Override
public long getItemId(int i) {
return i;
}
而获取View就要复杂一些了,也是最关键的,每次在屏幕上显示某个item时都需要调用该函数。
改方法的逻辑是,当某个View之前没有被获取过时,新建一个viewHolder,该类是用来储存view中的信息的,防止重复findViewById
,算是一个优化,该类的成员就是每个item中的组件,在这里就是一个TextView:
private final class ViewHolder{
TextView textView;
}
用viewHolder将数据存储起来,之后用setTag()
将其添加到view上,然后用之前写好的条目布局item_layout
渲染出一个View,将其放到view里;如果该view之前就被创建过,我们就用getTag()
将之前添加的数据拿回viewHolder
里。
最后,将对应条目的数据加载到viewHolder中,就完成了。
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
if(view == null){
viewHolder = new ViewHolder();
view = LayoutInflater.from(context).inflate(R.layout.item_layout, viewGroup, false);
viewHolder.textView = view.findViewById(R.id.text);
view.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) view.getTag();
}
//TextView textview = view.findViewById(R.id.text);
//textview.setText(data.get(i).getName());
viewHolder.textView.setText(data.get(i).getName());
Log.e("ShadyPi", "getView: "+i);
return view;
}
这个跟按钮点击差不多,在MainActivity.java
中设置一个监听及其点击响应函数即可:
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Log.e("ShadyPi", "click:"+i);
}
});