Android入门--ListView使用总结

ListView,简单理解成列表显示,目前大多数Android端的应用软件都会使用ListView,可见其在开发中的重要性,所以有必要深入理解掌握,下面开始总结:

首先,需要理解ListView的组成


从图中可以看出一个最简单的ListView的组成:

(1)ListView页面

(2)ListView的每一项

(3) 每一项中的数据

然后是ListView的功能:1,将数据填充到View中,2.响应点击事件

第1点,将数据填充到View中,就需要使用 适配器(Adapter) 来连接ListView和数据,让数据按照给定的布局显示在ListView中

第2点,响应事件事件,一般ListView都会有SetOnItemClickListener方法,用来响应点击事件,或者,在OnClick方法中一般会有参数为点击的item的索引和点击的item的View,只需要简单引用就能找到点击的item项


Adapter的分类:

ArrayAdapter,最简单的Adapter,用来绑定数组型数据

SimpleAdaper,使用最广的Adapter,灵活性高,可根据XML布局文件的不同而适配数据

SimpleCursorAdapter,对数据库操作时用的Adapter,根据从数据库获取到的数据进行适配

BaseAdapter,基础Adapter,需要用其他类来继承它,然后重写getView方法,能得到不同的适配

注:SimpleAdapter和BaseAdapter的区别:BaseAdapter可以实现在单个ListView的Item中添加按钮并实现点击事件,而SimpleAdapter不能对Item中的按钮等交互性控件的事件进行处理,只能对ListView的Item进行SetOnItemClickListener


以上是使用比较广的四种适配器,其实适配器种类还有很多,但是目的都是一样的--将数据和ListView适配,使数据能够在ListView中显示


下面通过代码来实际操作说明

1.通过ArrayAdapter使用ListView

一个最简单的ListView使用方法,使用ArrayAdapter:1).在布局文件中添加ListView标签;2).在代码中初始化ListView,得到实例,然后调用实例的sertAdapter方法,可以在setAdapter中创建匿名内部类Adapter();对于Adapter的设置很重要,因为在Adapter中需要指定显示的View样式和数据源,这样一个最简单的ListView就实现了;

package com.example.testarrayadapter;

import android.os.Bundle;
import android.app.Activity;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends Activity {

	// 定义数据源
	private String[] data = { "test01", "test02", "test03", "test04", "test05",
			"test06" };

	// 申明ListView
	private ListView list = null;

	// 申明适配器,Adapter中的数据是String类型的
	private ArrayAdapter<String> mArrayAdapter = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		// 绑定控件
		list = (ListView) findViewById(R.id.lv);

		// 创建新的ArrayAdapter,参数需要
		// 1,上下文对象
		// 2.XML布局文件,这里为了方便,使用的是系统自带的simple_list_item_1布局文件
		// 3.最后就是数据源
		mArrayAdapter = new ArrayAdapter<String>(this,
				android.R.layout.simple_list_item_multiple_choice, data);

		// 然后执行绑定适配器的操作,这样ListView就和数据进行了绑定
		list.setAdapter(mArrayAdapter);

		// 设置选择模式,这是在使用了带选择框的item布局时,可以通过设置设个属性来设置单选或者多选模式
		list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
	}
}


运行效果:



注:Android系统还提供了几种不同样式的item布局,包括带选择框的,带按钮的,各种不同样式,具体情况具体使用吧,我这里使用的是最简单的布局样式,仅显示一行文本



2.通过SimpleAdapter使用ListView

使用SimpleAdapter,首先创建Item布局文件,这是在ListView中单个Item显示的样式,然后在代码中初始化ListView,创建ArrayList<Hashmap<String,Object>>用于绑定数据,每一个Item中的数据将绑定到Hashmap中,这样ArrayList实例调用add方法就能将数据加入,然后创建SimpleAdapter的实例,添加数据和布局,最后调用ListView的SetAdapter方法,添加这个SimpleAdapter就能完成使用

首先是item的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/IV_item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="2dp"
        android:layout_marginTop="2dp"
        android:background="#dd3344"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:id="@+id/TV_item_top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/TV_item_top"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="2dp"
        android:layout_toRightOf="@+id/IV_item"
        android:background="#eedd33"
        android:gravity="center"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/TV_item_center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/IV_item"
        android:layout_alignLeft="@+id/TV_item_top"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/TV_item_top"
        android:layout_marginBottom="2dp"
        android:background="#23ed43"
        android:gravity="center"
        android:textSize="14sp" />

</RelativeLayout>

然后是activity_main的布局文件,整个页面就是一个简单的ListView:

 

<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"
    tools:context=".MainActivity" >

    <ListView
        android:id="@+id/LV_simple"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" >
    </ListView>

</RelativeLayout>

最后就是MainActivity中的代码:

package com.example.testsimpleadapter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	// 申明ListView
	private ListView mListView = null;

	// 申明SimpleAdapter
	private SimpleAdapter mSimpleAdapter = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// 初始化ListView
		mListView = (ListView) findViewById(R.id.LV_simple);

		// 初始化SimpleAdapter,参数为:
		// 1.上下文对象
		// 2.数据源,这里将数据源封装在下面的方法getData中
		// 3.布局文件,这里的布局文件就是之前做好的item布局文件
		// 4.对应HashMap中的键,用一个String型数组来封装
		// 5.对应的布局文件中的控件的id,用一个int型数组来封装
		mSimpleAdapter = new SimpleAdapter(this, getData(), R.layout.list_item,
				new String[] { "icon", "topText", "centerText" }, new int[] {
						R.id.IV_item, R.id.TV_item_top, R.id.TV_item_center });

		// 对ListView设置适配器
		mListView.setAdapter(mSimpleAdapter);

		// 设置ListView的每一项点击事件
		mListView.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
					long arg3) {

				// onItemClick事件中的参数:
				// arg0,Adapter的View,不太清楚,具体还需要再研究
				// arg1,点击的item界面的View,就是一个list_item界面,所以可以通过这里获取到控件中的内容
				// arg2,点击的item的索引,就是,点击的是第几个item

				// 这里可以看到,通过arg1就可以获取到点击的那个item界面的TextView控件,然后就能获取到控件上的内容
				TextView itemContent = (TextView) arg1
						.findViewById(R.id.TV_item_top);

				Toast.makeText(MainActivity.this,
						"你点击了 item " + arg2 + "内容是:" + itemContent.getText(),
						Toast.LENGTH_SHORT).show();
			}
		});
	}

	/**
	 * 获取数据源的方法
	 */
	private List<Map<String, Object>> getData() {
		List<Map<String, Object>> list_item = new ArrayList<Map<String, Object>>();

		for (int i = 0; i < 10; i++) {
			// 这里一定要注意,每次向list_item中添加的item_data必须是新建的HashMap实例
			// 也就是必须每次新建,每次添加,而不能一次新建循环添加
			// 所以这个new 语句必须放在for循环内
			Map<String, Object> item_data = new HashMap<String, Object>();
			item_data.put("icon", R.drawable.ic_launcher);
			item_data.put("topText", "Top test " + i);
			item_data.put("centerText", "simpleAdapter center " + i);
			list_item.add(item_data);
		}
		return list_item;
	}

}
运行效果图:


注:SimpleAdapter和SimpleCursorAdapter的区别仅仅在于数据源的不同,SimpleCursorAdapter是通过Cursor实例获取到数据库的内容,然后作为数据源传入SimpleCursorAdapter的参数,这里就不做记录


3.通过BaseAdapter使用ListView

使用BaseAdapter,因为BaseAdapter是抽象类,所以需要新建一个类继承自BaseAdapter类,然后调用ListView的SetAdapter时,使用这个新建的类作为参数,在BaseAdapter中需要重写几个方法,其中getView()方法是对View的适配,也是对ListView进行优化的一个关键方法,对于ListView的优化,以下内容来自网络:

第一种:没有任何处理,不建议这样写。如果数据量少看将就,但是如果列表项数据量很大的时候,会每次都重新创建View,设置资源,严重影响性能,所以从一开始就不要用这种方式

@Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View item = mInflater.inflate(R.layout.list_item, null);
            ImageView img = (ImageView)item.findViewById(R.id.img) 
            TextView title = (TextView)item.findViewById(R.id.title);
            TextView info = (TextView)item.findViewById(R.id.info);
            img.setImageResource(R.drawable.ic_launcher);
            title.setText("Hello");
            info.setText("world");
            
            return item;
        }
第二种ListView优化:通过缓存convertView,这种利用缓存contentView的方式可以判断如果缓存中不存在View才创建View,如果已经存在可以利用缓存中的View,提升了性能

public View getView(int position, View convertView, ViewGroup parent) {
            if(convertView == null)
            {
                convertView = mInflater.inflate(R.layout.list_item, null);
            }
            
            ImageView img = (ImageView)convertView.findViewById(R.id.img) 
            TextView title = (TextView)convertView.findViewById(R.id.title);
            TextView info = (TextView)ConvertView.findViewById(R.id.info);
            img.setImageResource(R.drawable.ic_launcher);
            title.setText("Hello");
            info.setText("world");
            
            return convertView;
        }

第三种ListView优化:通过convertView+ViewHolder来实现,ViewHolder就是一个静态类,使用 ViewHolder 的关键好处是缓存了显示数据的视图(View),加快了 UI 的响应速度。

当我们判断 convertView == null  的时候,如果为空,就会根据设计好的ListItem布局(XML),来为convertView赋值,并生成一个viewHolder来绑定converView里面的各个View控件(XML布局里面的那些控件)。再用convertViewsetTagviewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。(看下面代码中)

如果convertView不为空的时候,就会直接用convertViewgetTag(),来获得一个ViewHolder

//在外面先定义,ViewHolder静态类
    static class ViewHolder
    {
        public ImageView img;
        public TextView title;
        public TextView info;
    }
//然后重写getView
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if(convertView == null)
            {
                holder = new ViewHolder();
                convertView = mInflater.inflate(R.layout.list_item, null);
                holder.img = (ImageView)item.findViewById(R.id.img) 
                holder.title = (TextView)item.findViewById(R.id.title);
                holder.info = (TextView)item.findViewById(R.id.info);
                convertView.setTag(holder);
            }else
            {
                holder = (ViewHolder)convertView.getTag();
                holder.img.setImageResource(R.drawable.ic_launcher);
                holder.title.setText("Hello");
                holder.info.setText("World");
            }
            
            return convertView;
        }
下面是实例:

首先创建ListView中的item页面,这里的item页面和之前的SimpleAdapter中的item页面大致相同,只是在右边多加了一个按钮,所以就不贴出来了。

然后是MainActivity中,我这里为了方便是将继承自BaseAdapter类的子类mBaseAdapter写在MainActivity中的,也可以单独建个类文件来写,注意构造方法传参时要传入数据源;

package com.example.testbaseadapter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	// 申明ListView实例
	private ListView mListView = null;
	// 申明一个mBaseAdapter类的实例
	private mBaseAdapter mAdapter = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// 绑定ListView实例
		mListView = (ListView) findViewById(R.id.LV_show);
		// 初始化mBaseAdapter实例
		mAdapter = new mBaseAdapter(this);
		// 设置ListView实例的适配器
		mListView.setAdapter(mAdapter);
	}

	/**
	 * 获取数据的方法,这个和之前的SimpleAdapter一样,就不再赘述
	 */
	private List<Map<String, Object>> getData() {
		List<Map<String, Object>> list_item = new ArrayList<Map<String, Object>>();
		for (int i = 0; i < 10; i++) {
			Map<String, Object> item_data = new HashMap<String, Object>();
			item_data.put("icon", R.drawable.ic_launcher);
			item_data.put("topText", "TopText " + i);
			item_data.put("centerText", "this is centerText " + i);
			list_item.add(item_data);
		}
		return list_item;
	}

	/**
	 * 新建一个类mBaseAdapter继承自BaseAdapter
	 * 
	 */
	class mBaseAdapter extends BaseAdapter {
		private LayoutInflater mInflater;

		private Context mContext;

		// 构造方法,根据Context加载布局
		public mBaseAdapter(Context context) {
			mContext = context;
			mInflater = LayoutInflater.from(mContext);
		}

		// 获取数量,通过返回getData()的大小表示获取的数量
		@Override
		public int getCount() {
			return getData().size();
		}

		// 获取getData()中与指定索引对应的数据项
		@Override
		public Object getItem(int position) {
			return position;
		}

		// 获取在列表中与指定索引对应的行id
		@Override
		public long getItemId(int position) {
			return position;
		}

		// 这里是最重要的方法,ListView的优化也在这里进行
		@Override
		public View getView(final int position, View convertView,
				ViewGroup parent) {
			ViewHolder holder;
			// 如果缓存convertView为空,则需要创建View
			if (convertView == null) {
				// 为新建的convertView绑定布局
				convertView = mInflater.inflate(R.layout.list_item, null);
				holder = new ViewHolder();
				// 绑定各组件
				holder.imageView = (ImageView) convertView
						.findViewById(R.id.IV_item);
				holder.topTextView = (TextView) convertView
						.findViewById(R.id.TV_item_top);
				holder.centerTextView = (TextView) convertView
						.findViewById(R.id.TV_item_center);
				holder.clickButton = (Button) convertView
						.findViewById(R.id.BT_item);
				// 将设置好的布局保存到缓存中,并将其设置在Tag里,以便后面方便取出Tag
				convertView.setTag(holder);

			} else {
				holder = (ViewHolder) convertView.getTag();
			}
			// 对组件元素进行设置,比如设置在组件中要显示的内容
			holder.imageView.setImageResource(R.drawable.ic_launcher);
			holder.topTextView.setText(getData().get(position).get("topText")
					.toString());
			holder.centerTextView.setText(getData().get(position)
					.get("centerText").toString());
			
			//按钮的点击事件
			holder.clickButton.setOnClickListener(new OnClickListener() {

				@Override
				public void onClick(View v) {
					//这里获取到点击的item的position,并Toast显示
					Toast.makeText(mContext, "你点击了id=" + getItemId(position),
							Toast.LENGTH_LONG).show();
				}
			});
			return convertView;
		}
	}

	// ViewHolder静态类
	public static class ViewHolder {
		public ImageView imageView;
		public TextView topTextView;
		public TextView centerTextView;
		public Button clickButton;
	}

}

运行效果如图:




以上,简单总结了四种常用的Adapter和ListView结合使用的方法,其中需要重点掌握的是BaseAdapter,虽然看起来比较繁琐,还涉及到什么ListView性能优化,但是实际操作起来,和SimpleAdapter大体相似,多练习几遍,多敲敲代码就能熟练使用,以后还需要继续努力深入学习,加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值