Android 学习笔记(9)—— ListView

作者:夏至  欢迎转载,也请保留这段申明,谢谢

ListView绝对可以称得上是Android中最常用的UI空间之一,同时也是跟之前难度。几乎所有的应用程序都会应用到它。当我们的程序中有大量的数九需要展示的时候,就可以借助ListView来实现。我们最常用的就是手机设置那里啦。

是不是很熟悉,这里既有图片又有文字。是不是比我们以前学的有意思多无聊?

不过在实践这个功能之前呢,我们先来了解一下Adapter适配器的意思。

1、Adapter 适配器

可以这样简单理解MAC 。 Model(数据)—> Controller(以什么方式显示)—> View (用户界面)

而这个Adapter则是中间的这个Controller的部分。如果还不理解,那就理解成你的电脑的电源的适配器是有型号的,不同电脑对应不同的适配器。相当于一个220V交流电压进来时,以什么样的方式(适配器)传到电脑。当然这只是个人见解,如有错误,也欢迎指出。

图二呢,是Adapter的继承关系图。这里看看就可以了。我们重点来讲解Adapter的三种方法

·BaseAdapter:抽象类,实际开发中我们会继承这个类并且重写相关方法,用得最多的一个Adapter!

·ArrayAdapter:支持泛型操作,最简单的一个Adapter,只能展现一行文字~

·SimpleAdapter:同样具有良好扩展性的一个Adapter,可以自定义多种效果!

这里我们就简单讲解一下ArrayAdapter 和 BaseAdapter 这两个最常用的。

1.1 ArrayAdapter 文字表示

首先,我们先来实现一下文字的方式,即最上面的setting那里,我们不要图片,只显示文字。别急,我们先从简单的开始。效果如这样:

First,在layout那里,添加一个ListView的控件

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:orientation="vertical"
  4.     android:layout_width="match_parent"
  5.     android:layout_height="match_parent">
  6. <ListView
  7.         android:id="@+id/list_item"
  8.         android:layout_width="match_parent"
  9.         android:layout_height="wrap_content"
  10.     ></ListView>
  11. </LinearLayout>

在主activity那里,我们写上:

  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  1. protected void onCreate(Bundle savedInstanceState) {
  1. super.onCreate(savedInstanceState);
  2. setContentView(R.layout.activity_main);
  3. //要显示的数据
  4. String[] strs = {"基神","B神","翔神","曹神","J神"};
  5. //创建ArrayAdapter
  6. ArrayAdapter<String> adapter = new ArrayAdapter<String>
  7. (this,android.R.layout.simple_expandable_list_item_1,strs);
  8. //获取ListView对象,通过调用setAdapter方法为ListView设置Adapter设置适配器
  9. ListView list_test = (ListView) findViewById(R.id.list_test);
  10. list_test.setAdapter(adapter);
  11. }
  12. }

代码很简单,你也可以不先定义string,用list_test.add("");的方式添加。

1.2 ArrayAdapter 图文并茂

   接下来我们要实现的是这家伙,这里会用到自定义的知识,不会的先去学习一下自定义。

    

首先,我们先在layout层,创建一个xml文件。用来显示图片和文字。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:orientation="horizontal"
  4.     android:layout_width="match_parent"
  5.     android:layout_height="wrap_content">
  6. <ImageView
  7.         android:id="@+id/content_image"
  8.         android:layout_width="64dp"
  9.         android:layout_height="64dp"
  10.         android:scaleType="fitCenter"
  11.         android:baselineAlignBottom="true"
  12.         android:paddingLeft="8dp"
  13.     />
  14. <LinearLayout
  15.         android:layout_width="wrap_content"
  16.         android:layout_height="wrap_content"
  17.         android:paddingTop="5dp"
  18.         android:orientation="vertical">
  19. <TextView
  20.         android:id="@+id/text"
  21.         android:layout_width="wrap_content"
  22.         android:layout_height="wrap_content"
  23.         android:textColor="#1D1D1C"
  24.         android:gravity="center"
  25.         android:paddingLeft="10dp"
  26.         android:textSize="14sp"
  27.     />
  28. <TextView
  29.         android:id="@+id/text2"
  30.         android:layout_width="wrap_content"
  31.         android:layout_height="wrap_content"
  32.         android:gravity="center"
  33.         android:textColor="#B4B4B9"
  34.         android:paddingLeft="10dp"
  35.         android:layout_marginLeft="10dp"
  36.         android:layout_marginBottom="10dp"
  37.         android:textSize="12sp"
  38.     />
  39. </LinearLayout>
  40. </LinearLayout>

接下来,创建两个类,Content 和 ContentAdapter。

为什么要创建这两个类,因为你总不能把所有程序都扔在主函数那里把?是个正常人都不能忍,而java中,只要你的包名是一样的,那么就可以相互调用,这个IDE已经帮我们处理好了。那么在Content写上:

  1. public class Content {
  2. private String name,say;
  3. private int imageId;
  4. public Content(String name, String say, int imageId) {
  5.         this.name = name;
  6. this.imageId = imageId;
  7. this.say = say;
  8.     }
  9.     public String getName() {
  10.         return name;
  11.     }
  12.     public int getImageId() {
  13.         return imageId;
  14.     }
  15.     public String getSay() {
  16.         return say;
  17.     }
  18. }

接下来我们需要自定义一个适配器ContentAdapter,用来继承ArrayAdapter,并将泛型制定为Content类。

  1. public class ContentAdapter extends ArrayAdapter<Content>{
  2. private int resourceId;
  3. // context 表示我们要传入的内容,比如this
  4. // resource 表示我们要传进来刚刚新建的layout文件
  5. // List<Content> object 要传入的数据
  6. public ContentAdapter(Context context, int resource, List<Content> object) {
  7.     super(context, resource, object);
  8.     resourceId = resource;
  9. }
  10. @Override
  11. //converView 以前的布局的缓存
  12. // position 获取每一个Item的值,填充到制定的XML文件中
  13. // parent 当前布局会被加载到父布局中
  14. public View getView(int position, View convertView, ViewGroup parent) {
  15.     View view;
  16.     Content content = getItem(position); //获取当前的Content实例
  17.     // 优化,这样可以减少重复加载;layout 布局文件
  18.     if(convertView == null) { //如果刚开始创建
  19.     // LayoutInflater .. 表示动态加载布局,第二个参数我们一般选null
  20.     view = LayoutInflater.from(getContext()).inflate(resourceId, null);
  21. }
  22. else {
  23. view = convertView; //表示已经创建过了
  24. }
  25.     // 获取xml文件中的控件
  26.     ImageView ContentImage = (ImageView) view.findViewById(R.id.content_image);
  27.     TextView ContentName = (TextView)view.findViewById(R.id.text);
  28.     TextView ContentSay = (TextView)view.findViewById(R.id.text2);
  29.     // 重写方法,让图片和文字显示出来
  30.     ContentImage.setImageResource(content.getImageId());
  31.     ContentName.setText(content.getName());
  32.     ContentSay.setText(content.getSay());
  33. return view; //返回我们重新定制的布局
  34. }
  35. }

呼呼,就是这样,我已经把详细解释都注释在那里了,至于getView()方法,是每次我们在滚动屏幕时,都会被加载的。

然后是主activity啦。。。。

  1. public class MainActivity extends AppCompatActivity {
  2. private String[] name = {"自古屌丝多薄命","无形被黑 最为致命","我赵日天第一个不服","无敌锐神"};
  3. private String[] say = {"要脸你就输了","你的贱就是我的贱","我将带头日狗","断剑重铸之日 骑士归来之时"};
  4. private List<Content> contentList = new ArrayList<Content>();
  5. protected void onCreate(Bundle savedInstanceState) {
  6.     super.onCreate(savedInstanceState);
  7.     setContentView(R.layout.linearlayout);
  8.     initContens(); //初始化
  9.     ContentAdapter adapter = new ContentAdapter(MainActivity.this,
  10.     R.layout.content,contentList); // 传入参数,我们自定义的适配器
  11.     ListView listView = (ListView)findViewById(R.id.list_item);
  12.     listView.setAdapter(adapter); //显示出来
  13. // listView.setOnItemClickListener(new ArrayAdapterClick(this,contentList));
  14. }
  15. public void initContens(){
  16. contentList.add(new Content(name[0],say[0],R.drawable.image3));
  17. contentList.add(new Content(name[1],say[1],R.drawable.image4));
  18. contentList.add(new Content(name[2],say[2],R.drawable.image5));
  19. contentList.add(new Content(name[3],say[3],R.drawable.image6));
  20. }

这样就实现好了。不过呢,我们再为它添加一个点击事件,如果点了没有反应,那这个就没啥用了。

单击事件

  1. public class ArrayAdapterClick implements AdapterView.OnItemClickListener{
  2. private Context context;
  3. private List<Content> contentList;
  4. public ArrayAdapterClick(Context context,List<Content> contentList){
  5. this.context = context;
  6. this.contentList = contentList;
  7. }
  8. @Override
  9. public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
  10. Content content = contentList.get(position); //获取指定位置的数据
  11. Toast.makeText(context,content.getName()+"\n"+content.getSay(),Toast.LENGTH_SHORT).show();
  12. }
  13. }

然后我们再在主函数那里添加:

这样既ok啦。效果如图:

2、BaseAdapter

    在布局和Content类和ArrayAdapter是一样的,这里就不再赘述,这里我就讲不同点。 BaseAdapter 是个抽象类,所以里面的几个抽象方法我们都要重写。还是直接撸代码,部分注释我已经弄好了。

  1. public class BaseAdaperData extends BaseAdapter{
  2. private String[] name = {"自古屌丝多薄命","无形被黑 最为致命","我赵日天第一个不服","我良辰最喜欢对有能力的人出手","无敌锐神"};
  3. private String[] say = {"要脸你就输了","你的贱就是我的贱","我将带头日狗","我有一百种方法让你混不下去","断剑重铸之日 骑士归来之时"};
  4. // 这里初始化,我们在里面,用数组的方式
  5. private Content[] data= new Content[]{
  6. new Content(name[0],say[0],R.drawable.image3),
  7. new Content(name[1],say[1],R.drawable.image4),
  8. new Content(name[2],say[2],R.drawable.image5),
  9. new Content(name[3],say[3],R.drawable.image6),
  10. new Content(name[4],say[4],R.drawable.image7),
  11. };
  12. private Context context; // 因为初始化什么的都在里面了,所以我们就只要传入context就行了
  13. public BaseAdaperData(Context context){
  14. this.context = context;
  15. }
  16. // 不要也行,直接传context,只是用getContext()这样标准一点
  17. public Context getContext() {
  18. return context;
  19. }
  20. @Override
  21. public int getCount() {
  22. return data.length; //返回list所包裹的大小
  23. }
  24. @Override
  25. public Content getItem(int position) {
  26. return data[position]; //返回指定位置的内容
  27. }
  28. @Override
  29. public long getItemId(int position) {
  30. return 0;
  31. }
  32. @Override
  33. public View getView(int position, View convertView, ViewGroup parent) {
  34. View view;
  35. // 优化
  36. if(convertView == null){
  37. // getContext() 用context替代也行
  38. view = LayoutInflater.from(getContext()).inflate(R.layout.baseapaper,null);
  39. }else{
  40. view = convertView;
  41. }
  42. Content content = getItem(position); //获取实例
  43. ImageView image = (ImageView) view.findViewById(R.id.imageview);
  44. TextView ContentName = (TextView) view.findViewById(R.id.text);
  45. TextView ContentSay = (TextView) view.findViewById(R.id.text2);
  46. image.setImageResource(content.getImageId());
  47. ContentName.setText(content.getName());
  48. ContentSay.setText(content.getSay());
  49. return view;
  50. }
  51. }

看,和ArrayAdapter基本一样。详细注释可以看上面的ArrayAdapter。然后是主activity的

这样就ok啦,第三行是触发事件。

单击事件

  1. public class BaseAdapterDataClick implements AdapterView.OnItemClickListener{
  2. private BaseAdaperData object;
  3. private Context context;
  4. public BaseAdapterDataClick(Context context,BaseAdaperData object){
  5. this.context = context;
  6. this.object = object;
  7. }
  8. @Override
  9. public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
  10. Content content = object.getItem(position);
  11. Toast.makeText(context,content.getName()+"\n"+" "+content.getSay(),Toast.LENGTH_SHORT).show();
  12. }
  13. }

好了,这样基本就可以了,可以对比一下。只有多对比,多实践才能明白。效果如图:

其实上面的优化还不算够好,虽然我们已经对布局进行了优化,但是对控件的优化,还是每次都是调用View 的 findViewById()方法来获取一次控件的实现。所以,这里我们采用ViewHolder 来对这部分进行性能优化。修改 BaseAdaperData.java ,如下:

  1. public class BaseAdaperData extends BaseAdapter{
  2. private String[] name = {"自古屌丝多薄命","无形被黑 最为致命","我赵日天第一个不服","我良辰最喜欢对有能力的人出手","无敌锐神"};
  3. private String[] say = {"要脸你就输了","你的贱就是我的贱","我将带头日狗","我有一百种方法让你混不下去","断剑重铸之日 骑士归来之时"};
  4. //private String[] picture = {"R.drawable.image4","R.drawable.image5","R.drawable.image6","R.drawable.image7"};
  5. // 这里初始化,我们在里面,用数组的方式
  6. private Content[] data= new Content[]{
  7. new Content(name[0],say[0],R.drawable.image3),
  8. new Content(name[1],say[1],R.drawable.image4),
  9. new Content(name[2],say[2],R.drawable.image5),
  10. new Content(name[3],say[3],R.drawable.image6),
  11. new Content(name[4],say[4],R.drawable.image7),
  12. };
  13. private Context context; // 因为初始化什么的都在里面了,所以我们就只要传入context就行了
  14. public BaseAdaperData(Context context){
  15. this.context = context;
  16. }
  17. // 不要也行,直接传context,只是用getContext()这样标准一点
  18. public Context getContext() {
  19. return context;
  20. }
  21. @Override
  22. public int getCount() {
  23. return data.length; //返回list所包裹的大小
  24. }
  25. @Override
  26. public Content getItem(int position) {
  27. return data[position]; //返回指定位置的内容
  28. }
  29. @Override
  30. public long getItemId(int position) {
  31. return 0;
  32. }
  33. class ViewHolder{
  34. ImageView contentImage;
  35. TextView contentName;
  36. TextView contentSay;
  37. }
  38. public View getView(int position, View convertView, ViewGroup parent) {
  39. View view;
  40. // 优化
  41. ViewHolder viewHolder; // 对控件进行优化
  42. if(convertView == null){
  43. // getContext() 用context替代也行
  44. view = LayoutInflater.from(getContext()).inflate(R.layout.baseapaper,null);
  45. viewHolder = new ViewHolder(); //初始化
  46. viewHolder.contentImage = (ImageView) view.findViewById(R.id.imageview);
  47. viewHolder.contentName = (TextView) view.findViewById(R.id.text);
  48. viewHolder.contentSay = (TextView) view.findViewById(R.id.text2);
  49. view.setTag(viewHolder); // 将ViewHolder 储存在View中
  50. }else{
  51. view = convertView;
  52. viewHolder = (ViewHolder)view.getTag(); // 重新获得ViewHolder
  53. }
  54. Content content = getItem(position); //获取实例
  55. viewHolder.contentImage.setImageResource(content.getImageId());
  56. viewHolder.contentName.setText(content.getName());
  57. viewHolder.contentSay.setText(content.getSay());
  58. return view;
  59. }
  60. }

其他都不用改变,这样就可以啦。

这里唠叨几句,很多网上都说 BaseAdapter 比 ArrayAdapter 好用。这里都是一样的,如果你不太明白抽象类的应用,我建议你还是用ArrayAdapter ,相对而言,也比较容易理解,也足够你捣鼓很多东西了。没必要把自己拖入一个死胡同,适用自己的才是最好的。

来自为知笔记(Wiz)

时间: 2024-11-05 15:48:56

Android 学习笔记(9)—— ListView的相关文章

android学习笔记之ListView 和Adapter适配器

1.在学习Listview时候用到了Adapter适配器,定义MyAdapter时候需要继承ListAdapter接口,接口里很多方法没有实现,为了方便google工程师实现了个BaseAdapter类,我们在使用的时候可以继承这个抽象类,因此我们只需要完成几个抽象方法就可以了. public class Db_adapter extends BaseAdapter { private Context context; private List<Person> personlist; publ

Android学习笔记:ListView简单实用--显示文字列表

在activity中的编写如下代码: final List<String> items = new ArrayList<String>(); //设置要显示的数据,这里因为是例子,所以固定写死 items.add("item1"); items.add("item2"); items.add("item3"); ListView listView = (ListView) findViewById(R.id.listVie

Android学习笔记之ListView与Item的焦点冲突处理

由于ListView的Item需要焦点,Item里面的子控件(如ImageButton,Button,CheckBox等等)也需要焦点的时候,就会出现焦点冲突问题,导致Item无法获得焦点,无法相应Item的事件无法触发.这是就需要为其分配焦点,通常我们是屏蔽Item里面的子控件(暂时学的都是这样的,以后还不知道),有三种解决方案: (1)XML中对Item的子控件设置属性:                          android:focusable="false" (2)在

Android学习笔记之ListView的简单使用

(1) <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddi

Android学习笔记:ListView及BaseAdapter使用

ListView是Android中常用的重要组件之一,基本上所有软件基本都会使用ListView,所以要对ListView非常熟悉. 先看看程序效果图: ListView的样式很多,有纯文字型,带图片显示,带按钮的等等.本次演示一个带图片的ListView. ①布局文件: 在ListView程序中,布局文件相比其他普通控件会多出至少一个,其原因是还需要一个关于ListView里面内容条目的布局文件. 内容条目的布局文件 listview_item.xml : <?xml version="

Android学习笔记(四二):SQLite、ListView、ContextMenu

继续上一个例子,结合ListView中对SQLite进行操作. 通过CursorAdapter在ListView中的数据呈现 在上一个例子中,我们可以对SQLite中的数据库进行增删改查,将数据读到游标Cursor中,然后一一读出.在Android中可以通过CursorAdapter直接将数据映射到ListView中,如下处理: public class Chapter22Test1 extends ListActivity{    private SQLiteDatabase  db = nu

Android学习笔记(二十):回归简单的ListView

在之前连续对ListVew作了逐步深入的探讨,对于手持屏幕来讲,其实可以比较简单,如果别人愿意付钱,不在乎将代码再些一次,这是客户端的开发和复杂服务器的开发不同的地方.当然各人有各人的看法.绝大部分情况下,一个list元素可能左右各有一个widget就差不多,回归简约风格,这也是小尺寸屏幕和手指操作的特点. 在数据的传递,Java里面,具有<Key,Value>的Hash是非常重要的,可以方便增/删/改/查,如果我们不使用数据库存储,或者将数据存放在内存中,<Key,Value>是

Android学习笔记(十九):建立自己的ListView

在之前的例子中,我们通过设置adapter的getView()来编写我们所希望的UI,然而在面向对编程中,我们希望能够创建自己的ListView,例如类的名字为com.wei.android.learning.RatingView,只要在XML中用我们自己的RatingView对ListView来替代,就可以实现我们的风格,并前在源代码中向使用ListView一样简单调用就可以了. 实现的目标 在Android XML文件中,可以如下调用我们的RatingView: <com.wei.andro

[Android学习笔记]ListView中含有Button导致无法响应onItemClick回调的解决办法

转自:http://www.cnblogs.com/eyu8874521/archive/2012/10/17/2727882.html 问题描述: 当ListView的Item中的控件只是一些展示类控件时(比如TextView),注册ListView的监听setOnItemClickListener之后,当点击Item时候会触发onItemClick回调. 但是,当Item中存在Button(继承于Button)的控件时,onItemClick回调不会被触发. 解决方案: 在Item的布局文件

【转】 Pro Android学习笔记(十九):用户界面和控制(7):ListView

目录(?)[-] 点击List的item触发 添加其他控件以及获取item数据 ListView控件以垂直布局方式显示子view.系统的android.app.ListActivity已经实现了一个只含有一个ListView的Activity,并通过setListAdapter()方法来管理adapter.我们可以通过扩展ListActivity来实现. 我们要在整个屏幕上显示ListView,我们直接继承使用ListActivity,不需要在定义自己的layout XML文件,我们在上一学习中