Android开发之ListView


Android开发之ListView

/*

* Android开发之ListView

*

* Created on: 2011-8-7

* Author: blueeagle

* Email: liujiaxiang@gmail.com

*/

最近在学习android开发过程中,发现有关ListView这个类的问题和处理方式的问题比较多。需要总结学习一下。

要学习ListView,不得不学习Adapter。在学习之前,先考察类的继承关系:

ListView:

java.lang.Object

android.view.View

android.view.ViewGroup

android.widget.AdapterView<T extends android.widget.Adapter>

android.widget.AbsListView

android.widget.ListView

Adapter:

已知间接继承的子类

ArrayAdapter<T>,BaseAdapter,CursorAdapter,HeaderViewListAdapter,

ListAdapter,ResourceCursorAdapter,SimpleAdapter,SimpleCursorAdapter,

这里我也先不说我们在开发中经常会使用到什么类型的Adapter。先给几个应用程序截图来说明已经存在的ListView的应用,并对这些已经存在的ListView做实现DEMO。

单一的ListView

如图所示,这种ListView不存在任何复杂的内容,每行只显示一些文字。如果没有特殊要求的话,这是最简单最实用的一种ListView。

实现这种ListView有两种方式:

第一种是:不借助XML文件来直接实现:

源码如下:

/* * Android开发之ListView * ListViewExActivity.java * Created on: 2011-8-7 * Author: blueeagle * Email: liujiaxiang@gmail.com */ package com.blueeagle; import java.util.ArrayList; import android.app.Activity; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListView; public class ListViewExActivity extends Activity { private ListView listView; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); listView = new ListView(this); listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,getData())); setContentView(listView); } private ArrayList<String> getData(){ ArrayList<String> myData = new ArrayList<String>(); myData.add("思想决定行为 "); myData.add("行为形成习惯"); myData.add("习惯决定性格"); myData.add("性格决定命运"); return myData; } }


第二种方法是借助XML文件:

源码如下:

/* * Android开发之ListView * ListViewExActivity.java * Created on: 2011-8-7 * Author: blueeagle * Email: liujiaxiang@gmail.com */ package com.blueeagle; import java.util.ArrayList; import android.app.Activity; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListView; public class ListViewExActivity extends Activity { private ListView listView; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.myListView); listView = (ListView)findViewById(R.id.myListView); listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,getData())); } private ArrayList<String> getData(){ ArrayList<String> myData = new ArrayList<String>(); myData.add("思想决定行为 "); myData.add("行为形成习惯"); myData.add("习惯决定性格"); myData.add("性格决定命运"); return myData; } }


myListView.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ListView android:id="@+id/myListView" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>


说明:有时候我们在开发过程中,需要在一个没有xml的View中添加一个ListView控件,有时候我们可能需要在有xml文件描述的时候添加一个ListView控件。需要注意的是:setContentView()这个函数的先后顺序要写清楚。

在这种方法中我们使用了ArrayAdapter。

稍复杂点的ListView——添加了标题(描述)元素

如图所示,这种ListView只是比单一的ListView多了一个标题,或者说是描述的ListView,这种ListView应该是我们在实际开发中用的最多的一种ListView了。

同样的,实现这种ListView有两种方式。理论跟上面的一样,现在就举一种例子。

源码如下:

/* * Android开发之ListView * ListViewExTitleActivity.java * Created on: 2011-8-7 * Author: blueeagle * Email: liujiaxiang@gmail.com */ package com.blueeagle; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import android.app.Activity; import android.os.Bundle; import android.widget.ListView; import android.widget.SimpleAdapter; public class ListViewExTitleActivity extends Activity { private String[] myTitle = { "思想决定行为", "行为形成习惯", "习惯决定性格", "性格决定命运","狂热的Android开发者"}; private String[] myDescript = { "说话办事儿,首先要有一个好的思想,有了好思想,才能体现在行动上", "能够坚持的行动将成为习惯", "对事对人的习惯性行为表现为人的性格", "往往成就大事的人,都有着很好的性格", "狂热的Android程序员需要有一个好性格" }; private String[] myNote = { "备注1", "备注2", "备注3", "备注4","备注5" }; private ListView myListView; ArrayList<Map<String,Object>> mData= new ArrayList<Map<String,Object>>();; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); int lengh = myTitle.length; for(int i =0; i < lengh; i++) { Map<String,Object> item = new HashMap<String,Object>(); item.put("title", myTitle[i]); item.put("Descript", myDescript[i]); item.put("note", myNote[i]); mData.add(item); } myListView = new ListView(this); SimpleAdapter adapter = new SimpleAdapter(this,mData,R.layout.layout_item_1, new String[]{"title","Descript","note"},new int[]{R.id.title,R.id.descript,R.id.note}); myListView.setAdapter(adapter); setContentView(myListView); } }

layout_item_1.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#00ffff" android:textSize="22px" /> <TextView android:id="@+id/descript" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFFFFFFF" android:textSize="13px" /> <TextView android:id="@+id/note" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FF0000" android:textSize="13px" android:layout_gravity="right" /> </LinearLayout>

说明:在这个例子里面我们使用到了SimpleAdapter。看这个名字,简单的Adapter,其实不是那么简单。查看手册,可以知道其构造函数以及意义:

public SimpleAdapter (Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)

第一个context :SimpleAdapter所要运行关联到的视图。一般而言,就是这个SimpleAdapter所在的Activity,所以这个参数一般是this。

第二个是一个泛型只要是一个List就行,这一般会想到是ArrayList,而他内部存储的则是Map或者继承自Map的对象,比如HashMap。每一个ArrayList中的一行就代表着呈现出来的一行,Map的键就是这一行的列名,值也是有列名的。

第三个资源文件,就是说要加载这个两列所需要的视图资源文件,也就是布局文件,可以定义成.xml的文件。

第四个参数是一个数组,主要是将Map对象中的名称映射到列名,一一对应

第五个是将第四个参数的值一一对象的显示(一一对应)在接下来的int形的id数组中,这个id数组就是LayOut的xml文件中命名id形成的唯一的int型标识符

在程序中:

Map<String,Object> item = new HashMap<String,Object>(); item.put("title", myTitle[i]); item.put("Descript", myDescript[i]); item.put("note", myNote[i]); mData.add(item);


这段代码里,一个item设置了三个值,也可以设置更少或者是更多的值。如果设置了更少或者更多的值,相应的需要在.xml文件里修改布局,同时修改程序里SimpleAdapter的第四个和第五个参数。即修改程序中:

SimpleAdapter(this,mData,R.layout.layout_item_1, new String[]{"title","Descript","note"},new int[]{R.id.title,R.id.descript,R.id.note});


这段代码的参数,可以增加也可以减少。

特别要注意的是,在item里设置的值,还可以是图形或者是别的视图类型,如下实例。

ListView——添加了标题(描述)元素以及图片元素

如图所示,这种ListView只是比前面的ListView多了一个图标。这正是在上一个例子后面所说明的一样。只是添加了几行源码,如下:

ListViewExTitleActivity.java

添加了:

item.put("image", R.drawable.icon); SimpleAdapter adapter = new SimpleAdapter(this,mData,R.layout.layout_item_1, new String[]{"image","title","Descript","note"},new int[]{R.id.imageicon,R.id.title,R.id.descript,R.id.note});


layout_item_1.xml

添加了:

<ImageView android:id="@+id/imageicon" android:layout_width="wrap_content" android:layout_height="wrap_content" />

这里需要注意的是:如果不喜欢每一个item的布局,可以修改xml布局文件里的结构,调整图片位置,字体位置等。

ListView——自定义特别的ListView

如图所示,我们在程序开发过程中,经常会遇见各种特定样式,类型等等的需求,在图中这种情况下,上述几种例子都不能很好的解决,这个时候就要自己定义了。自定义ListView是一个很有意思的过程。

ListView在绘制前会调用getCount()方法得到绘制次数,这个次数,实际上就是ListView的Item项数 ,然后实例化自己定义的一个Adapter,一般常用的有两种Adapter,一种是BaseAdapter,适合较少的List Item;另一种是BaseAdapter的子类:ArrayAdapter,适合较多,较复杂的List Item。这些Adapter都通过getView()方法一项一项的绘制ListView,所以我们可以在这里面根据position(当前绘制的ID)来任意的修改绘制的内容。

在举例之前,不得不说一下这个特别重要的函数getView():

查看手册可以得到getView的解释:

public abstract View getView (int position, View convertView, ViewGroup parent)

获取用于显示数据集中指定位置上的数据的视图。你可以手工创建一个视图, 也可以从 XML 布局文件中展开视图。展开视图时,父视图(GridView、ListView 等) 将应用默认的布局参数,除非你使用inflate(int, android.view.ViewGroup, boolean) inflate(int, android.view.ViewGroup, boolean)指定根视图,并指定附加到根元素。

参数

position

要从适配器中取得的视图的位置.

convertView

要重用的旧视图,如果可能。注意,在使用之前你应该检查该视图是否非空, 并且是适当的类型。如果不能转化该视图来正确显示数据,该方法将创建新视图。

parent

该视图最终关联到的父视图。

返回值

指定位置的数据对应的视图。

看的晕,不要紧,从例子入手:

首先我们来写java文件。我们写一个自己的adapter继承于BaseAdapter

/* * Android开发之ListView * ListViewExTitleActivity.java * Created on: 2011-8-7 * Author: blueeagle * Email: liujiaxiang@gmail.com */ package com.blueeagle; import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; public class ListViewExTitleActivity extends Activity { private String[] myTitle = { "思想决定行为", "行为形成习惯", "习惯决定性格", "性格决定命运","狂热的Android开发者","狂热的Android开发者"}; private String[] myDescript = { "说话办事儿,首先要有一个好的思想,有了好思想,才能体现在行动上", "能够坚持的行动将成为习惯", "对事对人的习惯性行为表现为人的性格", "往往成就大事的人,都有着很好的性格", "狂热的Android程序员需要有一个好性格" ,"狂热的Android开发者"}; private String[] myNote = { "备注1", "备注2", "备注3", "备注4","备注5" ,"狂热的Android开发者"}; ListView myListView = null; NewTypeAdapter myAdapter = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); myListView = new ListView(this); myAdapter = new NewTypeAdapter(this); myListView.setAdapter(myAdapter); myListView.setOnItemClickListener(new AdapterView.OnItemClickListener(){ @Override public void onItemClick(AdapterView<?> arg0,View arg1,int arg2,long arg3){ arg1.setBackgroundColor(Color.BLACK); System.out.println(arg2); Toast.makeText(ListViewExTitleActivity.this,"您选择了" + myTitle[arg2], Toast.LENGTH_LONG).show(); } }); setContentView(myListView); } class NewTypeAdapter extends BaseAdapter { private Context mContext; private int[] colors = new int[]{Color.RED,Color.BLUE,Color.GREEN,Color.WHITE}; public NewTypeAdapter(Context context) { mContext = context; } @Override public int getCount() { // TODO Auto-generated method stub return myTitle.length; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return position; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub System.out.println(position); ImageView myIamge = null; TextView myTextTitle = null; TextView myTextDescript = null; TextView myTextNote = null; //if (convertView == null) { convertView = LayoutInflater.from(mContext).inflate(R.layout.layout_item_1, null); myIamge = (ImageView) convertView.findViewById(R.id.imageicon); myTextTitle =(TextView) convertView.findViewById(R.id.title); myTextDescript= (TextView) convertView.findViewById(R.id.descript); myTextNote= (TextView) convertView.findViewById(R.id.note); // } // else try{ int j = position%colors.length; convertView.setBackgroundColor(colors[j]); myTextTitle.setText(myTitle[position]); myTextDescript.setText(myDescript[position]); myTextNote.setText(myNote[position]); myIamge.setImageResource(R.drawable.icon); } catch(Exception e){ e.printStackTrace(); } return convertView; } } }


layout_item_1.xml:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ImageView android:id="@+id/imageicon" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#00ffff" android:textSize="22px" /> <TextView android:id="@+id/descript" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFFFFFFF" android:textSize="13px" /> <TextView android:id="@+id/note" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FF0000" android:textSize="13px" /> </LinearLayout>


说明:首先说明的是,这个例子自定义了类:NewTpyeAdapter,继承BaseAdapter,当然要实现BaseAdapter的各个成员方法。程序OnCreate方法中主要有四个内容:实例化NewTypeAdapter,实例化ListView,然后利用myListView.setAdapter(myAdapter);将ListView和NewTypeAdapter绑定。

这里需要特别注意的是:如果ListViewExTitleActivity继承的是Activity,则必须要加上setContentView(myListView)这句,如果继承的是ListActivity,则不用加啦,因为其本身就是一个List了。

接下来就是我们的最重要的方法,getView()方法。

在说getView方法之前说几个可能出现的问题:

1. getView()方法不会被调用;

2. 当ListView在一个屏幕内显示不全的时候,拖动后的数据会重复。

3. 如果在ListView中的某个Item中加入一个按钮的话,这个Item的点击事件将消失。

下面来解答这些问题:getView()这个方法的调用是有条件的。我在开始试验的时候,getView()方法一直不会被调用,后来才发现,如果getCount ()的返回值为0的话,则不会被调用。因此需要把BaseAdapter的成员方法都写全。

对于重复问题:如上面源码,如果加入了if(convertView ==null)则表示其一屏幕显示了从数据空间读取的内容,滚动后则不会再从数据空间读取,而是从现有空间读取。手册中说使用的时候先判断是否为空,但是我这里去掉了这个if语句,则能够实现效果,但是可能带来效率问题,这样的话每次回滚,则每次会重绘。

对于加入按钮点击事件消失的问题,是因为按钮的焦点抢夺了listview项的焦点。因此listview的项就点击不到了。

总结:

以上说了四种ListView的实现方式。当然第四种还可以引申开去。比如我们可以继承ArrayAdapter;也可以在每个ListItem中加入一个按钮,加入按钮只需要添加该按钮的消息响应函数就可以了。

相信经过上面的学习,对ListView这个类应该有一定的掌握了,一些大大小小的问题应该都能够解决了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值