把东西变成你自己的才叫搞定
在移动端一个很好的地方就是我们可以用手指往下滑动,而列表正好适合这一点,它可以随着你的滑动往下扩展,这节我们就来玩转列表,看看神奇的列表在安卓中要怎么实现。
建一个新工程,叫MyList。我们搞一个public class MyListActivity extends ListActivity。请注意这一跨世纪的变化,我们继承的是ListActivity。
我们再简单地给它一个layout,里面就放一个TextView,运行看看。
报错了,它说你的content必须有一个id为android.R.id.list的ListView,这就是ListActivity和普通Activity的区别。那我们加上吧!
这个时候,我们的程序运行起来了。
这里我们得到第一个hint:ListActivity必须要有一个ListView,并且android:id="@id/android:list"
但是这里没什么意义,我们的ListView里面没东西。那么怎么给ListView中加东西呢?说起来你都不会相信,只要在onCreate中添加:
List items = new ArrayList();
items.add("item1");
items.add("item2");
items.add("item3");
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, items);
setListAdapter(adapter);
首先,我们准备一个List,然后弄一个ArrayAdapter,最后调用setListAdapter将adapter放进去,这里要注意的是android.R.layout.simple_ list_item_1,相信大家都注意到了,不管是android:id="@id/android:list"还是android.R.layout.simple_list_item_1,这些都是android系统自带的东西。我们来看看效果先:
这样的效果显然不能满足我们的需求,怎么办呢?我们其实可以自己定义列表的样式的,我们注意到android.R.layout.simple_ list_item_1就是系统的一个布局文件,我们自己来搞一个布局文件不就行了吗?
我们定义一个item.xml
这时,我们要指定TextView的id,ArrayAdapter
如果我们在一个item中还想要一个文本呢?
运行看看:
那这个文本能变吗?显然,之前的程序不能满足要求,我们至少要提供一个String对。这个需求用ArrayAdapter已经不能满足要求了,我们要使用SimpleAdapter,在用之前,我们把LinearLayout的orientation改成水平。代码改成:
List> items = new ArrayList>();
HashMap map = null;
map = new HashMap();
map.put("item", "hello");
map.put("itemTwo", "world");
items.add(map);
map = new HashMap();
map.put("item", "hello too");
map.put("itemTwo", "world too");
items.add(map);
SimpleAdapter adapter = new SimpleAdapter(this, items, R.layout.item, new String[]{"item", "itemTwo"}, new int[]{R.id.item, R.id.itemTwo});
setListAdapter(adapter);
这里我们用一个HashMap,这个HashMap中put了两条数据,分别是item和itemTwo,这两个数据作为SimpleAdapter构造的第四个参数传进去,第五个参数传递的是两个TextView的id,这里请大家仔细研究对应关系。我们看下效果:
是我们期望的效果,但是样子不太好呢,至于怎么修改样式大家自己搞好啦!
有了SimpleAdapter,我们想要多少个TextView都能显示了,但是我们还有更高的需求,看看人家微信多牛,那个List,有图片,有时间啥的,还有小红点,我们也想做一个嘞!这个效果用SimpleAdapter也能做出来哦!我们来看看吧。首先搞定布局文件:
这次我们换了相对布局,这个对于你来说应该是完全没问题的,小儿科啦。下面是代码:
List> items = new ArrayList>();
HashMap map = null;
Resources resources = getResources();
Bitmap[] bitmaps = new Bitmap[4];
bitmaps[0] = BitmapFactory.decodeResource(resources, R.drawable.image01);
bitmaps[1] = BitmapFactory.decodeResource(resources, R.drawable.image02);
bitmaps[2] = BitmapFactory.decodeResource(resources, R.drawable.image03);
bitmaps[3] = BitmapFactory.decodeResource(resources, R.drawable.image04);
for(int i=1;i<=4;i++) {
map = new HashMap();
Bitmap image = bitmaps[i-1];
String name = String.format("sun %02d", i);
String desc = String.format("我是燕姿%02d", i);
map.put("image", bitmaps[i-1]);
map.put("name",name);
map.put("desc",desc);
items.add(map);
}
SimpleAdapter adapter = new SimpleAdapter(this, items, R.layout.item, new String[]{"image", "name" ,"desc"}, new int[]{R.id.image, R.id.name, R.id.desc});
adapter.setViewBinder(new ViewBinder() {
public boolean setViewValue(View view, Object data,
String textRepresentation) {
System.out.println(data);
if( (view instanceof ImageView) && (data instanceof Bitmap) ) {
ImageView imageView = (ImageView) view;
Bitmap bitmap = (Bitmap) data;
imageView.setImageBitmap(bitmap);
System.out.println("here");
return true;
}
return false;
}
});
setListAdapter(adapter);
这个代码我们要说一说了,首先我准备了四个图片,然后我们通过资源ID将图片转换成为图Bitmap保存下来,这一过程主要是Resources resources = getResources();和bitmaps[0] = BitmapFactory.decodeResource(resources,R.drawable.image01);,然后我们将我们要显示的东西放到map中去,注意,这次我们的map是HashMap
正好在听燕姿的歌,就找了几张头像咯。到这里我很想知道,如果我们的item多一些会怎样,我们来试下
看到了吧,ListView自己加了滑动的功能,而且不影响上面的text,不得不说android的组件做的不错,不愧是google出品。那要是我们在ListView下面再放一个text呢?啊哈,我们发现看不到下面的TextView了,原因大家应该都知道了,我们用weight属性可以解决这个问题:
这里还有一点需要大家注意一下,我们打开程序,发现控制台只输出到08
这是为什么呢?因为我们的手机现在只显示到第八个item,那么我们往下滑动的时候,你再看
滑到第几个就出现第几个,也就是说我们ViewBinder中的setViewValue不是一次性把所有item都加载进来,而是显示到哪个加载哪个,这称为懒加载,好处和坏处大家自己分析吧。同样,当01不出现在屏幕中的时候,它就被释放了,下次再出现需要重新加载。大家可以自己做实验的哦!
好了,到这里还有一个重要的问题没有讲,那就是怎么响应item的点击,相信你已经猜到,肯定是绑定一个Listener,我们看看代码
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
Toast.makeText(this, "you click " + position, Toast.LENGTH_SHORT).show();
super.onListItemClick(l, v, position, id);
}
哈哈,因为我们是继承ListActivity,所以只需要重载onListItemClick就行了,这里position就指定了我们点击哪个item。注意,这里我们用了Toast.makeText(this, "you click " + position,Toast.LENGTH_SHORT).show();,Toast是一个系统控件,什么效果你试试就知道啦,注意,它需要一个Context,这里我们传递了this,最后别忘了调用show。
我们的List还支持长按,这里我们就要自己设置Listener了
getListView().setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
System.out.println("you long click " + position);
return true;
}
});
注意这里返回了true,就不会再响应click了,假如返回false,还会响应click的。
到了这里这节内容介绍了一半了,觉得累了的同学可以休息下,下次接着看另一半,那另一半是什么呢?其实我们还可以不继承ListActivity,我们直接用ListView来做也可以,只要我们得到ListView就行。我们再定义一个Activity,来实现这种方式,长按item 0 的时候跳转到这个Activity。布局文件我们用自己的id
还有列表项的布局文件:
设置adapter也是一样的:
package com.example.mylist;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class MyListViewActivity extends Activity {
private ListView listView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.listview);
listView = (ListView) findViewById(R.id.myownList);
List items = new ArrayList();
items.add("item1");
items.add("item2");
items.add("item3");
ArrayAdapter adapter = new ArrayAdapter(this, R.layout.listviewitem, R.id.mylisttextview, items);
listView.setAdapter(adapter);
}
}
还有一个超级重头戏,我们可以自己继承BaseAdapter来实现自己的Adapter,怎么样,不错吧,来看看怎么实现吧,我们再定义一个activity,长按第二个item的时候跳转到它,既然把这里说破了,我们可以想象,其实ArrayAdapter和SimpleAdapter都是继承自BaseAdapter
首先我们看下我们的adapter
package com.example.adapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public class MyOwnAdapter extends BaseAdapter {
public int getCount() {
// TODO Auto-generated method stub
return 0;
}
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
return null;
}
}
首先getCount函数返回这个list中总共有多少个item,而getView就是返回每个item所对应的View。这两个函数就可以满足我们的要求了,那么我们的getItem和getItemId有什么用呢?我们留到下节再来揭晓。我们的getCount和getView如下:
public int getCount() {
// TODO Auto-generated method stub
return 10;
}
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
TextView textView = new TextView(context);
textView.setText("hello");
textView.setTextSize(50);
System.out.println(position + " is called");
return textView;
}
这样就会有10个TextView哦,我们看看效果
最后还有一点,ListActivity其实可以不需要setContentView的,我们把它去掉也能运行,因为它里面有默认的布局了。
好了,总结一下:
1、 ListActivity
2、 ListView
3、 ArrayAdapter
4、 SimpleAdapter和ViewBinder
5、 Toast用法
6、 继承自BaseAdapter的自定义Adapter入门
7、 怎么从一个drawable的id得到对应的Bitmap:先getResources,在BitmapFactory.decodeResource
这节的例子在:http://download.csdn.net/detail/yeluoxiang/7337439,欢迎大家下载,下节我们会涉及到ListView的性能优化,敬请期待!