0%

Android ListView

ListView控件

这个控件就是一个列表框控件,比较的常见,基本每个软件都有的。

控件性质

其实这个和之前的那个下拉框和文本提示框基本上性质一样,都是控件-适配器-数据,这三个东西构成的。

简单适配器

其实这里说的简单,是指的适配器比较简单,用安卓给我们提供的适配器:android.R.layout.simple_list_item_1。
布局:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.android_study9.MainActivity" >

<ListView
android:id="@+id/Lv"
android:layout_width="match_parent"
android:layout_height="match_parent"

></ListView>

</RelativeLayout>

布局的话呢就是一个列表框。
代码实现方面的话呢,也是比较简单的。

1
2
3
4
5
6
7
8
9
10
11
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,getData());
Lv.setAdapter(adapter);

/*

*/

private String[] getData()
{
return new String[]{"a","b","c","d"};
}

自定义适配器

这个是我们比较关注的,因为功能强大而且漂亮。

首先我们需要一个布局:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >

<ImageView
android:id="@+id/iv_ava"
android:layout_width="40dip"
android:layout_height="40dip"
android:src="@drawable/ic_launcher"
/>
<TextView
android:id="@+id/tx_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Wker"
android:layout_toRightOf="@+id/iv_ava"
android:layout_centerVertical="true"
android:layout_marginLeft="70dip"
/>
<TextView
android:id="@+id/tx_des"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="最帅的男人"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/tx_name"
/>

</RelativeLayout>

实现效果

这个时候我们需要给他们ID,因为我们需要在后面用到。
主布局的话呢和简单的是一样的。

然后因为我们是自定义的适配器,所以我们需要自己设置一个继承于适配器的一个类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package com.example.android_study9.adapter;

import java.util.List;

import com.example.android_study9.R;
import com.example.android_study9.model.finendmodel;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class FriendsAdapter extends BaseAdapter{

public List<finendmodel> mData;
private Context ctx;

public FriendsAdapter(Context ctx,List<finendmodel> mData) {
this.ctx = ctx;
this.mData = mData;


}

@Override
public int getCount() {//决定列表的个数
return mData.size();
}

@Override
public Object getItem(int arg0) {//根据arg0获取对应Item的数据
return mData.get(arg0);
}

@Override
public long getItemId(int arg0) {//根据arg0获取对应Item的ID
return arg0;
}
@Override
public View getView(int arg0, View arg1, ViewGroup arg2) {//创建列表的Item视图
View v = arg1;
holder h = null;
if(v == null)
{
v = View.inflate(ctx, R.layout.picture, null);
h = new holder();
h.iv_ava = (ImageView) v.findViewById(R.id.iv_ava);
h.tx_name = (TextView) v.findViewById(R.id.tx_name);
h.tx_des = (TextView) v.findViewById(R.id.tx_des);
v.setTag(h);
}else
{
h = (holder) v.getTag();
}
finendmodel f = mData.get(arg0);
h.iv_ava.setImageResource(f.getImgId());
h.tx_name.setText(f.getName());
h.tx_des.setText(f.getDes());
return v;
}

private static class holder
{
private ImageView iv_ava;
private TextView tx_name;
private TextView tx_des;
}

}

说难的话呢也不是很难,但也不算是简单,首先构造方法中需要传递一个设备上下文,需要一个List的泛型数据,这个泛型的类是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.example.android_study9.model;

public class finendmodel {
private int imgId;
private String name;
private String des;
public int getImgId() {
return imgId;
}
public void setImgId(int imgId) {
this.imgId = imgId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
}

主要是用来存储我们的图片ID,名称和说明的。
getCount的话呢返回我们的List的个数,也就是我们的项目数目,getItem的话呢就是返回当前这个项目的数据,getItemId的话呢就是返回Item的ID,其实也及时把他的参数返回回去就好了(一般是),最关键的就是getView这个方法。
首先我们先是构造了一个内部类,这个内部类是静态的,目的是为了能够更好的释放内存,类里面存储了我们需要用到的数据,在我们的getView中,我们需要返回当前Item项目的一个View视图,这个视图我们通过: View.inflate(ctx, R.layout.picture, null);来获取,第二个参数,是我们自定义的一个布局。
然后我们new了一个我们的内部类,用于存储对应的控件,然后设置标签给这个View,为什么要这么做呢?因为我们如果每加载一个项目,都要加载布局,然后找控件,占用的资源太多了,而且速度慢,这个时候安卓提供给我们一个缓存机制,也就是参数传递给我们的View arg1,如果这个不为null,就是当前项目的一个缓存,这个时候我们只需要判断是不是为null,不是的话呢就用之前的这个项目,那么我们的内存就会比较的快了,为什么可以这样,因为我们缓存的也就是当我们往下滑动,看不到的那部分丢弃的,这个时候,再通过这个内部类,我们就可以实现一个减少内存的一个效果了,然后我们设置空间属性,最后将我们的View返回回去。
构造完毕这个类之后我们编写主窗体:

1
2
3
mAdapter = new FriendsAdapter(this, getData1());
Lv = (ListView) findViewById(R.id.Lv);
Lv.setAdapter(mAdapter);

getData就是用来返回数据的。

1
2
3
4
5
6
7
8
9
10
11
12
private List<finendmodel> getData1()
{
List<finendmodel> list = new ArrayList<finendmodel>();
for (int i = 0; i < 20; i++) {
finendmodel f = new finendmodel();
f.setDes("Wker"+i);
f.setName("Wker"+i+i);
f.setImgId(R.drawable.ic_launcher);
list.add(f);
}
return list;
}

其实也就是返回回去一个finendmodel泛型的List集合,然后我们可以增加两个点击事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
String txt = ((finendmodel)mAdapter.getItem(arg2)).getName();
Toast.makeText(MainActivity.this, txt, Toast.LENGTH_SHORT).show();;
}
});
Lv.setOnItemLongClickListener(new OnItemLongClickListener() {

@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
String txt = ((finendmodel)mAdapter.getItem(arg2)).getDes();
Toast.makeText(MainActivity.this, txt, Toast.LENGTH_SHORT).show();
return true;//是否执行单击,true不执行
}
});

看名字就知道了,第一个是单击,第二个是长按,需要注意的是长按的返回值决定了是否允许点击事件。
mAdapter.getItem(arg2)这个getItem方法使我们自己重写的,返回的也就是项目,以为我们知道这个返回来的就是一个finendmodel,我们可以强转,然后再从里面获取数据就好了。
效果图