ListView原本是只能显示一段文本的,如果想要在ListView中显示更加丰富的内容就需要对ListView进行定制。假设要使得每个ListView子项显示水果图片和文字。
简单的显示ListView使得每个子项左边显示图片,右边显示文字。
1.定义一个实体类
实体类中包含ListView子项所要显示的内容资源,比如新建一个Fruit类,有name和imageId两个属性,用于保存子项显示的内容。那么标识子项显示的文本,图片使用图片的id来替代图片资源。
public class Fruit {
private String name;
private int imageId;
public Fruit(String name,int imageId){
this.name = name;
this.imageId = imageId;
}
public String getName(){
return name;
}
public int getImageId(){
return imageId;
}
}
2.定义适配器类
因为ListView中的数据是需要使用适配器类进行的。
在适配器类的构造函数中传入要显示的数据。Listobjects表示要显示的数据,textViewResourceId表示子项采用的布局的id。
public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId;
public FruitAdapter(Context context,int textViewResourceId,List<Fruit> objects){
super(context,textViewResourceId,objects);
resourceId = textViewResourceId;
}
@Override
public View getView(int position,View convertView,ViewGroup parent){
Fruit fruit = getItem(position);
View view;
view=LayoutInflater.from(getContext())
.inflate(resourceId, null);
ImageView fruitImage = (ImageView)view
.findViewById(R.id.fruit_image);
TextView fruitName = (TextView)view
.findViewById(R.id.fruit_name);
fruitImage.setImageResource(fruit.getImageId());
fruitName.setText(fruit.getName());
return view;
}
}
3.编写子项的布局文件
因为要显示图片和文字,所以使用一个ImageView和一个TextView就足够了。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/fruit_name"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
/>
</LinearLayout>
4. 在要显示ListView的Activity的布局中增加ListView控件
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
5.在Activity文件中对ListView的数据进行显示
首先定义了一个List列表用来存放数据,在设置完Activity布局文件之后,首先现对List列表进行初始化,将数据送到List列表中。然后初始化适配器类,适配器中的构造函数传入的三个参数,第一个传入的是Activity本身,然后是ListView列表子项的布局文件的id,最后就是初始化之后的List列表。最后对Activity布局文件中的ListView列表设置一下适配器。就能显示结果了。
public class DisplayMessageActivity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<Fruit>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_display_message);
initFruits();
FruitAdapter adapter = new FruitAdapter(DisplayMessageActivity.this,R.layout.fruit_item,fruitList);
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
private void initFruits(){
Fruit apple = new Fruit("apple",R.drawable.back);
fruitList.add(apple);
Fruit banana = new Fruit("banana",R.drawable.back);
fruitList.add(banana);
Fruit orange = new Fruit("orange",R.drawable.back);
fruitList.add(orange);
Fruit watermelon = new Fruit("watermelon",R.drawable.back);
fruitList.add(watermelon);
Fruit pear = new Fruit("pear",R.drawable.back);
fruitList.add(pear);
Fruit grape = new Fruit("grape",R.drawable.back);
fruitList.add(grape);
Fruit pineapple = new Fruit("pineapple",R.drawable.back);
fruitList.add(pineapple);
Fruit strawberry = new Fruit("strawberry",R.drawable.back);
fruitList.add(strawberry);
Fruit cherry = new Fruit("cherry",R.drawable.back);
fruitList.add(cherry);
Fruit mango = new Fruit("mango",R.drawable.back);
fruitList.add(mango);
}
}
6.ListView子项的点击事件
只需要设置一下子项的事件监听器就好。
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//do something with item
}
});
7.ListView的性能优化
首先就是ListView滑动的时候ListView子项的出现是一个绘制的过程。这个绘制的过程中需要调用到Adapter适配器类中的getView()函数。
@Override
public View getView(int position,View convertView,ViewGroup parent){
Fruit fruit = getItem(position);
View view;
view = LayoutInflater.from(getContext())
.inflate(resourceId, null);
ImageView fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
TextView fruitName = (TextView)view.findViewById(R.id.fruit_name);
fruitImage.setImageResource(fruit.getImageId());
fruitName.setText(fruit.getName());
return view;
}
每次getView的时候 最后返回的View对象都是被重新创建出来的,然而getView函数中的第二个参数convertView中是保存着之前加载好的View对象的缓存的。所以可以通过使用convertView来优化。
View view;
if(convertView == null){
view = LayoutInflater.from(getContext()).inflate(resourceId, null);
}else{
view = convertView;
}
先判断一下convertView是否为空,如果为空,那就重新生成一个View,如果不为空表明这个View之前已经加载过了,有缓存存在,可以直接使用。
同样的道理,在getView函数中每次都需要查找控件
ImageView fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
TextView fruitName = (TextView)view.findViewById(R.id.fruit_name);
我们可以自己创建一个类来保存这些控件的信息,在Adapter类内部定义一个ViewHolder类来保存每个View类的空间信息。
class ViewHolder{
ImageView fruitImage;
TextView fruitName;
}
然后再getView中进行优化
@Override
public View getView(int position,View convertView,ViewGroup parent){
Fruit fruit = getItem(position);
View view;
ViewHolder viewHolder;
if(convertView == null){
view = LayoutInflater.from(getContext())
.inflate(resourceId, null);
viewHolder = new ViewHolder();
viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);
view.setTag(viewHolder);
}else{
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.fruitImage
.setImageResource(fruit.getImageId());
viewHolder.fruitName.setText(fruit.getName());
return view;
}
以上是对ListView学习的记录。