动手学Android之八——搞定列表

把东西变成你自己的才叫搞定

         在移动端一个很好的地方就是我们可以用手指往下滑动,而列表正好适合这一点,它可以随着你的滑动往下扩展,这节我们就来玩转列表,看看神奇的列表在安卓中要怎么实现。

         建一个新工程,叫MyList。我们搞一个public class MyListActivity extends ListActivity。请注意这一跨世纪的变化,我们继承的是ListActivity。

         我们再简单地给它一个layout,里面就放一个TextView,运行看看。


         报错了,它说你的content必须有一个id为android.R.id.list的ListView,这就是ListActivity和普通Activity的区别。那我们加上吧!

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/text_view" 
        />
    
    <ListView
        android:id="@id/android:list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        ></ListView>

</LinearLayout>

         这个时候,我们的程序运行起来了。


         这里我们得到第一个hint:ListActivity必须要有一个ListView,并且android:id="@id/android:list"

         但是这里没什么意义,我们的ListView里面没东西。那么怎么给ListView中加东西呢?说起来你都不会相信,只要在onCreate中添加:

List<String> items = new ArrayList<String>();
items.add("item1");
items.add("item2");
items.add("item3");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <TextView
        android:id="@+id/item"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:textColor="#FF0000"
        ></TextView>

</LinearLayout>

         这时,我们要指定TextView的id,ArrayAdapter<String> adapter = newArrayAdapter<String>(this, R.layout.item, R.id.item,items);,看看效果吧:



         如果我们在一个item中还想要一个文本呢?

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <TextView
        android:id="@+id/item"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:textColor="#FF0000"
        ></TextView>
    
    <TextView
        android:id="@+id/itemTwo" 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:textColor="#FF0000"
        android:text="我能变吗?"
        />

</LinearLayout>

         运行看看:


         那这个文本能变吗?显然,之前的程序不能满足要求,我们至少要提供一个String对。这个需求用ArrayAdapter已经不能满足要求了,我们要使用SimpleAdapter,在用之前,我们把LinearLayout的orientation改成水平。代码改成:

List<HashMap<String,String>> items = new ArrayList<HashMap<String,String>>();
HashMap map = null;
map = new HashMap<String, String>();
map.put("item", "hello");
map.put("itemTwo", "world");
items.add(map);
map = new HashMap<String, String>();
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也能做出来哦!我们来看看吧。首先搞定布局文件:

<?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="wrap_content" >

    <ImageView
        android:id="@+id/image"
        android:layout_width="60dp"
        android:layout_height="60dp"
        />
    
    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:textColor="#FF0000"
        android:layout_toRightOf="@id/image"
        android:layout_alignTop="@id/image"
        />
    
    <TextView
        android:id="@+id/desc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:textColor="#FF0000"
        android:layout_toRightOf="@id/image"
        android:layout_alignBottom="@id/image"
        />

</RelativeLayout>

         这次我们换了相对布局,这个对于你来说应该是完全没问题的,小儿科啦。下面是代码:

List<HashMap<String,Object>> items = new ArrayList<HashMap<String,Object>>();
HashMap<String,Object> 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<String,Object>();
	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<String,Object>类型的,这样它才可能既放String,又放Bitmap,下面就是重头戏了,我们调用了adapter.setViewBinder。这里为什么要搞一个ViewBinder呢?不得不说android设计得巧妙,我们的TextView默认只要给它一个String就好了,但是我们的ImageView呢,是给一个drawable的id,还是给一个Bitmap,还是别的,android就说了,我给你一个ViewBinder,怎么绑定数据和View,你自己决定!在这里,我们判断了if( (view instanceof ImageView) && (data instanceof Bitmap)),然后imageView.setImageBitmap(bitmap);,最后返回true。找得到重点吗?这里我要说的是返回true,这是告诉系统,ok,到此结束了,不要去使用默认的了。我们想,在TextView的时候,我们没有绑定ViewBinder,为什么能正常,因为系统默认给TextView对应的就是String,而ImageView对应的却不是Bitmap,在这里如果我们返回false,照样没法显示图片,不信你试试。好了,说了这么多,来看看效果吧。



         正好在听燕姿的歌,就找了几张头像咯。到这里我很想知道,如果我们的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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <TextView
        android:layout_width="match_parent" 
        android:layout_height="wrap_content"
        android:text="@string/owntext"
        />

    <ListView
        android:id="@+id/ownList" 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ></ListView>
    
</LinearLayout>

         还有列表项的布局文件:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <TextView
        android:id="@+id/mylisttextview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:textColor="#FF0000"
        />

</LinearLayout>

         设置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<String> items = new ArrayList<String>();
		items.add("item1");
		items.add("item2");
		items.add("item3");
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(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的性能优化,敬请期待!



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值