android菜鸟学习笔记14----Android控件(三) ListView的简单使用

MVC模式

MVC的基本原理就是通过Controller连接View和Model。当View中所显示的数据发生变化时,会通知Controller,然后由Controller调用Model中的相关方法执行相应的数据修改操作。反之,当Model中的数据发生变化时,也会通知Controller,由Controller通知View更新显示内容。如此一来,就使得数据部分与视图部分相分离,任何一方发生改变都不会影响到另一方。

而在android中,MVC的一个常见应用就是ListView显示数据。V代表的就是显示控件;M代表的是各种数据源,可以是自己定义的List或者数组,也可以是数据库,文件等;C代表的是Adapter类,android中比较常见的adapter有:BaseAdapter,ArrayAdapter,SimpleAdapter等。

ListView通过setAdapter方法实现了其和一个Adapter对象的绑定,Adapter一般通过getView()方法返回当前列表项所要显示的View对象,完成了对Model中数据的读取。

当Model发生变化时,会调用BaseAdapter.notifyDataSetChanged()方法通知组件数据已然变化,此时Adapter就会调用getView()方法重新显示组件内容。

ListView:间接继承自抽象类AdapterView

常见方法:

void  setOnItemClickListener(AdapterView.OnItemClickListener listener) 

void  setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) 

void  setAdapter(ListAdapter adapter) 

Adapter:是一个接口

主要的方法:

abstract int  getCount()  返回要显示的item总数

abstract Object  getItem(int position)  根据item索引返回该item

abstract long  getItemId(int position)  返回item的id。

abstract View  getView(int position, View convertView, ViewGroup parent)返回一个用来展示数据源中索引为position的View对象。

BaseAdapter是一个间接实现了Adapter接口的抽象类

自定义Adapter继承BaseAdapter时,需要提供上面四个方法的实现。主要要实现的是getCount()和geView()方法。

ArrayAdapter<T>, CursorAdapter, SimpleAdapter则直接继承自BaseAdapter,实现了其抽象方法。

ListView示例1:展示一个字符串数组中的各个字符串。

 1 main_layout.xml:
 2
 3 <?xml version="1.0" encoding="utf-8"?>
 4
 5 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 6
 7     android:layout_width="match_parent"
 8
 9     android:layout_height="match_parent"
10
11     android:orientation="vertical" >
12
13     <ListView
14
15         android:id="@+id/listview"
16
17         android:layout_width="wrap_content"
18
19         android:layout_height="wrap_content"
20
21         />
22
23 </LinearLayout>

MainActivity.java:

 1 public class MainActivity extends Activity {
 2
 3
 4
 5       private String[] strs;
 6
 7       @Override
 8
 9       protected void onCreate(Bundle savedInstanceState) {
10
11            // TODO Auto-generated method stub
12
13            super.onCreate(savedInstanceState);
14
15            setContentView(R.layout.main_layout);
16
17            strs = new String[]{"aaa","bbb","ccc","ddd","eee","fff","ggg","hhh","iii"};
18
19            ListView lv = (ListView) findViewById(R.id.listview);
20
21            lv.setAdapter(new MyBaseAdapter());
22
23
24
25       }
26
27       class MyBaseAdapter extends BaseAdapter{
28
29            @Override
30
31            public int getCount() {
32
33                  return strs.length;
34
35            }
36
37            @Override
38
39            public Object getItem(int position) {
40
41                  // TODO Auto-generated method stub
42
43                  return null;
44
45            }
46
47            @Override
48
49            public long getItemId(int position) {
50
51                  return 0;
52
53            }
54
55            @Override
56
57            public View getView(int position, View convertView, ViewGroup parent) {
58
59                  TextView tv = null;
60
61                  tv = new TextView(MainActivity.this);
62
63                  Log.i("listview", position+"get view");
64
65                  tv.setText(strs[position]);
66
67                  tv.setTextSize(40);
68
69                  tv.setTextColor(Color.RED);
70
71                  return tv;
72
73            }
74
75       }
76
77 }

运行结果:

注意到,每次滚动屏幕显示新的item,或将滚出屏幕上方的item重新显示出来都会调用getItem()方法。而上面的代码中每次都会新建一个TextView,这样做是存在问题的。

getView(int position, View convertView, ViewGroup parent),其中参数convertView在允许的情况下,会保存旧的View实例,以便拿来复用。所以,可以利用该参数来优化上面的getView()实现。

代码修改如下:

 1 public View getView(int position, View convertView, ViewGroup parent) {
 2
 3
 4
 5                  TextView tv = null;
 6
 7                  Log.i("listview", position+"get view");
 8
 9                  if(convertView == null){
10
11                       tv = new TextView(MainActivity.this);
12
13                  }
14
15                  else{
16
17                       tv = (TextView) convertView;
18
19                  }
20
21                  tv.setText(strs[position]);
22
23                  tv.setTextSize(40);
24
25                  tv.setTextColor(Color.RED);
26
27                  return tv;
28
29 }

其实,若只是显示数组中的内容,直接使用ArrayAdapter会比较方便:

MainActivity.java修改如下:

 1 private String[] strs;
 2
 3       @Override
 4
 5       protected void onCreate(Bundle savedInstanceState) {
 6
 7            // TODO Auto-generated method stub
 8
 9            super.onCreate(savedInstanceState);
10
11            setContentView(R.layout.main_layout);
12
13            strs = new String[]{"aaa","bbb","ccc","ddd","eee","fff","ggg","hhh","iii"};
14
15            ListView lv = (ListView) findViewById(R.id.listview);
16
17            ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strs);
18
19            lv.setAdapter(adapter);
20
21
22
23       }

运行结果:

其中android.R.layout.simple_list_item_1是系统自带的一个布局id。

一般来说,在ListView中显示的东西可能更加复杂点,只靠一个TextView肯定解决不了,这时,就可以为ListView中的item根据需要编写一个布局文件。

如:item_layout.xml:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2
 3     android:layout_width="match_parent"
 4
 5     android:layout_height="match_parent"
 6
 7     android:orientation="horizontal" >
 8
 9     <ImageView
10
11         android:layout_width="wrap_content"
12
13         android:layout_height="wrap_content"
14
15         android:src="@drawable/hero"
16
17         />
18
19     <TextView
20
21         android:id="@+id/tv_name"
22
23         android:layout_width="wrap_content"
24
25         android:layout_height="wrap_content"
26
27         android:textSize="35sp"
28
29         />
30
31 </LinearLayout>

用于在线性布局中水平显示一个图片和一个字符串。

修改MyAdapter内部类的getView():

 1 public View getView(int position, View convertView, ViewGroup parent) {
 2
 3
 4
 5                  View view = null;
 6
 7                  Log.i("listview", position+"get view");
 8
 9                  if(convertView == null){
10
11                       view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_layout, null);
12
13                  }
14
15                  else{
16
17                       view =  convertView;
18
19                  }
20
21                  TextView tv = (TextView) view.findViewById(R.id.tv_name);
22
23                  tv.setText(strs[position]);
24
25                  return view;
26
27            }

运行结果:

另一种可能常用的Adapter是SimpleAdapter。

构造函数:SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)

context指定上下文

data指定存放数据的list对象,list中存放的是Map对象。

resource指定item的布局文件id

from和to是有序的,两者中的元素必须一一对应,from中存放的是list中每个map对象中的key值,to存放的是显示对应key获取的值的控件的id。

如:item_layout.xml:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2
 3     android:layout_width="match_parent"
 4
 5     android:layout_height="match_parent"
 6
 7     android:orientation="horizontal" >
 8
 9     <ImageView
10
11         android:id="@+id/iv"
12
13         android:layout_width="wrap_content"
14
15         android:layout_height="wrap_content"
16
17         />
18
19     <TextView
20
21         android:id="@+id/tv_name"
22
23         android:layout_width="wrap_content"
24
25         android:layout_height="wrap_content"
26
27         android:textSize="35sp"
28
29         />
30
31 </LinearLayout>

MainActivity.java中修改如下:

 1 protected void onCreate(Bundle savedInstanceState) {
 2
 3            // TODO Auto-generated method stub
 4
 5            super.onCreate(savedInstanceState);
 6
 7            setContentView(R.layout.main_layout);
 8
 9            ListView lv = (ListView) findViewById(R.id.listview);
10
11            List<Map<String,Object>> data = new ArrayList<Map<String,Object>>();
12
13            Map<String,Object> map = new HashMap<String, Object>();
14
15            map.put("img", R.drawable.hero);
16
17            map.put("str", "aaa");
18
19            data.add(map);
20
21            map = new HashMap<String, Object>();
22
23            map.put("img", R.drawable.hero);
24
25            map.put("str", "bbb");
26
27            data.add(map);
28
29            map = new HashMap<String, Object>();
30
31            map.put("img", R.drawable.hero);
32
33            map.put("str", "ccc");
34
35            data.add(map);
36
37            map = new HashMap<String, Object>();
38
39            map.put("img", R.drawable.hero);
40
41            map.put("str", "ddd");
42
43            data.add(map);
44
45            map = new HashMap<String, Object>();
46
47            map.put("img", R.drawable.hero);
48
49            map.put("str", "eee");
50
51            data.add(map);
52
53
54
55            SimpleAdapter sa = new SimpleAdapter(this, data, R.layout.item_layout, new String[]{"img","str"}, new int[]{R.id.iv,R.id.tv_name});
56
57            lv.setAdapter(sa);
58
59 }

显示结果:

关于ListView的事件监听:

AdapterView中定义了几个设置事件监听的方法,如:

void  setOnItemClickListener(AdapterView.OnItemClickListener listener)

void  setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener)

ListView间接继承了AdapterView,所以,要处理事件监听时,可以调用ListView中相关的方法。

注:如果调用了ListView的setOnClickListener()方法,会报如下错误:

java.lang.RuntimeException: Don‘t call setOnClickListener for an AdapterView. You probably want setOnItemClickListener instead

setOnItemClickListener()方法示例:

 1 ListView lv = (ListView) findViewById(R.id.listview);
 2
 3            lv.setOnItemClickListener(new OnItemClickListener() {
 4
 5                  @Override
 6
 7                  public void onItemClick(AdapterView<?> parent, View view,
 8
 9                             int position, long id) {
10
11                       Log.i("listview","onClick");
12
13                       Log.i("listview",view.toString());
14
15                       Log.i("listview",position+"");
16
17                       Log.i("listview",id+"");
18
19                       TextView tv = (TextView) view.findViewById(R.id.tv_name);
20
21                       Toast.makeText(MainActivity.this, tv.getText(), Toast.LENGTH_LONG).show();
22
23                  }
24
25            });

运行结果:

ListView先学到这,等学了数据库操作,也许会用到CursorAdapter等,用到时再学。

时间: 2024-10-23 19:38:23

android菜鸟学习笔记14----Android控件(三) ListView的简单使用的相关文章

Android开发学习笔记-自定义组合控件的过程

自定义组合控件的过程 1.自定义一个View 一般来说,继承相对布局,或者线性布局 ViewGroup:2.实现父类的构造方法.一般来说,需要在构造方法里初始化自定义的布局文件:3.根据一些需要或者需求,定义一些API方法: ----------------------------------4.根据需要,自定义控件的属性,可以参照TextView属性: 5.自定义命名空间,例如: xmlns:itheima="http://schemas.android.com/apk/res/<包名&

Android开发学习笔记-自定义组合控件

为了能让代码能够更多的复用,故使用组合控件.下面是我正在写的项目中用到的方法. 1.先写要组合的一些需要的控件,将其封装到一个布局xml布局文件中. <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="

如果写一个android桌面滑动切换屏幕的控件(三)

下面我们把这个控件内嵌到Layout中做一些动画和展示,效果图: 这个子控件可以上下移动,可以左右滑动,如果上下滑动距离大于左右滑动距离,则必须上下滑动 这样来写onTouch事件: @Override public boolean onTouchEvent(MotionEvent ev) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMov

android菜鸟学习笔记12----Android控件(一) 几个常用的简单控件

主要参考<第一行代码> 1.TextView: 功能与传统的桌面应用开发中的Label控件相似,用于显示文本信息 如: 1 <TextView 2 3 android:layout_width="wrap_content" 4 5 android:layout_height="wrap_content" 6 7 android:textColor="#0000ff" 8 9 android:textSize="40sp

Android学习笔记:常用控件 RadioGroup和CheckBox

RadioGroup和CheckBox是android的常用控件,本文自做简单介绍和学习笔记,所以所用的控件样式选用android默认的样式. 先看下代码实现的效果图 图中,上面两个(male和female)为一个RadioGroup中的两个RadioButton,下面三个为CheckBox. 一个RadioGroup里面的内容只可单选,CheckBox可多选. 接下来是代码部分 布局文件代码activity_main.xml : <LinearLayout xmlns:android="

android学习笔记(2)EditText控件的学习

对应若水老师的第五课 一,设置一个输入框 添加控件: <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="52dp" <!--本控件顶部距离上一个控件的距离--> /> 二,消除输入框的聚焦 方法一: <EditText android:layout_wi

android菜鸟学习笔记30----Android使用百度地图API(一)准备工作及在应用中显示地图

1.准备工作: 百度地图API是免费开放的,但是需要申请API Key: 1)先注册一个百度开发者帐号 2)进入百度开放服务平台http://developer.baidu.com/ 3)进入LBS云 4)点击右上角的API控制台,没有登录的话会先跳转到登录页面,登录成功之后就进入应用控制台了: 5)点击创建应用: 应用类型选择Android SDK,注意下面的安全码,格式是数字签名+应用包名,中间用分号分隔.数字签名的获得: Eclipse中window->Preferences->Andr

android菜鸟学习笔记7----android布局(二)

3.FrameLayout:帧布局 如同Flash或者photoshop中图层的概念,在上面的图层遮盖下面的图层,没被遮到的地方仍然显示出来. 右击res/layout,然后在弹出的菜单中选择new,然后选择Android Xml File,要新建FrameLayout布局文件,就选择FrameLayout作为其根节点即可.文件名为frame_layout.xml. 代码如下: 1 <?xml version="1.0" encoding="utf-8"?&g

android菜鸟学习笔记6----android布局(一)

Android应用的UI组件都是继承自View类,View类表示的就是一个空白的矩形区域.常用的组件如TextView.Button.EditText等都直接或间接继承自View. 此外,View还有一个重要的子类ViewGroup,该类可以用来包含多个View组件,本身也可以当做一个View组件被其他的ViewGroup所包含,由此,可以构建出非常复杂的UI界面. 常用的布局管理器如FrameLayout.LinearLayout.RelativeLayout等都直接继承自ViewGroup.