您的位置:首页 > 移动开发 > Android开发

2014-10-27Android学习------布局处理(八)------自定义ListView的监听事件和Adapter的实现-----城市列表应用程序

2014-10-29 21:25 941 查看
写一篇文章很辛苦啊!!!

转载请注明,联系请邮件nlp30508@qq.com

我学习Android都是结合源代码去学习,这样比较直观,非常清楚的看清效果,觉得很好,今天的学习源码是网上找的个CityList 源码 百度搜就知道很多下载的地方 我写的东西有可能比较乱,如果单一的篇章没看明白,请看上一篇文章

上篇文章 地址:/article/7942723.html

与之相关的布局文件 地址:/article/7942719.html

这篇文章主要说的就是 当我们的ListView是自己的定义的时候,我们该怎么去实现他们,前面我们介绍过使用系统的

id @id/android:list 这样在实现布局的activity类里面我们是不用去通过资源文件找到他们,而是一个简单的

SimpleAdapter(

上下文,

数据data,

资源布局文件的id,

键值(这个键值必须跟data包含于data里面的键值,string类型,也必须跟布局文件上面的空间的id相匹配),

int[]数组,这个数组就是布局文件的里面的构件在资源文件中的id号,并且他们需要和string长度相匹配,还有一 一对应)

构造函数 ,然后简单的调用setAdapter()即可。然后再实现它的item点击事件就可以了。

void onItemClick(AdapterView<?> parent, View view, int position, long id)

与之相关的文章地址为:/article/7943712.html

回顾下SimpleAdapter的实现方法,接下来我们来看看自定义的ListView该怎么实现,看看两者之间的区别是什么:

视图效果:



1.申明一个ListView 对象:

private ListView mCityLit;

2.在OnCreate(Bundle)里面初始化找到它:

mCityLit = (ListView) findViewById(R.id.city_list);

3.实现它的item点击响应事件

mCityLit.setOnItemClickListener(new CityListOnItemClick());

这里重点也就是要将的就出来了, 看看setOnItemClickListener的参数是什么,是一个类,这个类是自定义的

接下来我们看看这个类。

这里我们必须存在这样一个意思,要用到ListView 就必须要用到Adapter 那么我们这个自定义的类必然跟Adapte有关系的

就是说我们的mCityList必然有个setAdapter操作的

1.定义一个Adapter对象

private BaseAdapter adapter;

我们顺便看看Android文档中关于Adapter的知识:



2.这样的BaseApater 满足不了我们的,我们必须自己去构造自己的Adapter才行

因为:BaseAdapter是一个基类,没有实现绑定数据的功能

使用BaseAdapter的话需要重载四个方法,这些方法分别是getCount,getItem,getItemId,最后一个最重要的是getView,getView函数为什么重要呢?因为它是用来刷新它所在的ListView的。它在什么时候调用的呢?就是在每一次item从屏幕外滑进屏幕内的时候,或者程序刚开始的时候创建第一屏item的时候。

先必须介绍下相关的变量

变量:private String[] sections;// 存放存在的汉语拼音首字母 就是当前城市名称是开头的字母是什么,放在这个数组

// 里面 ,具体有没有26个字母需要看有多少城市的名字,这些名字包不包括26个字母中

// 的每一个字母

变量:private HashMap<String, Integer> alphaIndexer;

// 存放存在的汉语拼音首字母和与之对应的列表位置

// 这个变量就是 A 字母 应该放在视图上面列表的哪个位置 例如下图中的M 和N

看图解释:



所以创造出自己的Adapter

//ListAdapter 就是我们自己自定义的Adapter 它继承 BaseAdapter

private class ListAdapter extends BaseAdapter

{

private LayoutInflater inflater;//布局填充器

private List<CityModel> list;// List数组,数组元素是CityModel 定义请看后面的代码

//构造函数,参数: 上下文 ,List数组

public ListAdapter(Context context, List<CityModel> list)

{

//由于它是一个内部类,所以这个布局填充器就可以用当前的activity的类的布局来填充

this.inflater = LayoutInflater.from(context);

this.list = list;

alphaIndexer = new HashMap<String, Integer>();//Map对象,键值为String value为int

sections = new String[list.size()];//有多少个城市

for (int i = 0; i < list.size(); i++)

{

// 当前汉语拼音首字母

String currentStr = list.get(i).getNameSort();//list.get(i)是一个类

// 上一个汉语拼音首字母,如果不存在为“ ”

String previewStr = (i - 1) >= 0 ? list.get(i - 1).getNameSort() : " ";

if (!previewStr.equals(currentStr))

{//如果两个城市的首字母不相同,需要在列表中增加这个字母的位置

String name = list.get(i).getNameSort();

alphaIndexer.put(name, i);//放一个i 这个i很重要,它表示"M"显示在哪里

sections[i] = name;//当前的这个i对应的城市的名称的首字母

}

}

}

@Override

public int getCount()

{ //有多少个城市需要显示

return list.size();

}

@Override

public Object getItem(int position)

{ //当前是那个城市

return list.get(position);

}

@Override

public long getItemId(int position)

{ //返回当前item的值

return position;

}

//继承BaseAdapter 我们需要重载这个方法 这个就是用来刷新你的View视图的

@Override

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

{//这个函数主要是就是当我们的城市非常的多的时候,我们滑动屏幕,视图是需要不断更新的

ViewHolder holder;//要显示在界面上的两个控件

if (convertView == null)

{//如果视图不可以重用的话,我们需要用到备用视图

convertView = inflater.inflate(R.layout.list_item, null);//填充布局

holder = new ViewHolder();

holder.alpha = (TextView) convertView.findViewById(R.id.alpha);

holder.name = (TextView) convertView.findViewById(R.id.name);

convertView.setTag(holder);

} else

{//如果视图可以重用的话,

holder = (ViewHolder) convertView.getTag();

}

holder.name.setText(list.get(position).getCityName());

String currentStr = list.get(position).getNameSort();

String previewStr = (position - 1) >= 0 ? list.get(position - 1).getNameSort() : " ";

if (!previewStr.equals(currentStr))

{

holder.alpha.setVisibility(View.VISIBLE);

holder.alpha.setText(currentStr);

} else

{

holder.alpha.setVisibility(View.GONE);

}

return convertView;

}

private class ViewHolder

{//CityList布局页面中相对布局里面放置的两个widget,

TextView alpha;//对应的是26个字母

TextView name;//对应的是城市的名称

}

}

特别提供:


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

Since: API
Level 1

Get a View that displays the data at the specified position in the data set. You can either create a View manually or inflate it from an XML layout file. When
the View is inflated, the parent View (GridView, ListView...) will apply default layout parameters unless you use
inflate(int,
android.view.ViewGroup, boolean)
to specify a root view and to prevent attachment to the root.


Parameters

positionThe position of the item within the adapter's data set of the item whose view we want.
convertViewThe old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the
correct data, this method can create a new view. Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see
getViewTypeCount()
and
getItemViewType(int)
).
parentThe parent that this view will eventually be attached to

Returns


A View corresponding to the data at the specified position.

position是指当前dataset的位置,通过getCount和getItem来使用。如果list向下滑动的话那么就是最低端的item的位置,如果是向上滑动的话那就是最上端的item的位置。conert是指可以重用的视图,即刚刚出队的视图。parent应该就是list。

关于getView原创地址:/article/7778411.html

3.自定义setAdapter函数:

private void setAdapter(List<CityModel> list)
{
if (list != null)
{
adapter = new ListAdapter(this, list);
mCityLit.setAdapter(adapter);
}

}
这里有行代码就是:mCityLit.setAdapter(adapter);

这行代码就告诉我们了 ListView设置了适配器 这个适配器使我们自定义的ListAdapter对象

4.那么setAdapter(List<CityModel> list)谁来调用呢,放在初始化函数里面最好了:

@Override

protected void onCreate(Bundle savedInstanceState) {

// TODO Auto-generated method stub

super.onCreate(savedInstanceState);

setContentView(R.layout.city_list);

mCityLit = (ListView) findViewById(R.id.city_list);

letterListView = (MyLetterListView) findViewById(R.id.cityLetterListView);

//..........

setAdapter(mCityNames);//给mCityList设置Adapter

mCityLit.setOnItemClickListener(new CityListOnItemClick());//添加点击事件

}

5.实现item的点击事件:

class CityListOnItemClick implements OnItemClickListener

{

@Override

public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3)

{

CityModel cityModel = (CityModel) mCityLit.getAdapter().getItem(pos);

//点击事件就是打印一个吐司 告诉你当前你选择的城市是哪个

Toast.makeText(CityList.this, cityModel.getCityName(), Toast.LENGTH_SHORT).show();

}

}

到这里这个自定义的ListView就实现完成了。

CityModel的定义:

public class CityModel {

private String CityName; //城市名字

private String NameSort; //城市首字母

public String getCityName()

{

return CityName;

}

public void setCityName(String cityName)

{

CityName = cityName;

}

public String getNameSort()

{

return NameSort;

}

public void setNameSort(String nameSort)

{

NameSort = nameSort;

}

}

1.变量:private ArrayList<CityModel> mCityNames;

2.赋值:mCityNames = getCityNames();

3.getCityNames()函数的实现:

private ArrayList<CityModel> getCityNames()
{
ArrayList<CityModel> names = new ArrayList<CityModel>();
Cursor cursor = database.rawQuery("SELECT * FROM T_City ORDER BY NameSort", null);
for (int i = 0; i < cursor.getCount(); i++)
{
cursor.moveToPosition(i);
CityModel cityModel = new CityModel();
cityModel.setCityName(cursor.getString(cursor.getColumnIndex("CityName")));
cityModel.setNameSort(cursor.getString(cursor.getColumnIndex("NameSort")));
names.add(cityModel);
}
return names;
}


这里是从数据库中调用城市的名称和首字母 具体的请看我下篇文章。

转载请注明,联系请邮件nlp30508@qq.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐