第十一章 Android 常用的ListView

1. ListView

  ListView应该算是Android 中最常见的控件之一了,几乎所有的应用都会用到ListView。y由于我们的手机屏幕空间有限,能够一次性在屏幕中显示的内容不多。当程序中的数据量较多的时候,我们通过使用ListView允许用户通过手指滑动的方式将屏幕外的数据滑动到屏幕内,同时去除掉原有的数据。

1.1 ListView的类结构:

java.lang.Object
 ↳ android.view.View
  ↳ android.view.ViewGroup
   ↳ android.widget.AdapterView<T extends android.widget.Adapter>
    ↳ android.widget.AbsSpinner
     ↳ android.widget.Spinner

1.2 ListView的职责

1.将数据填充到布局当中
2.处理点击事件

1.3 列表显示的三个元素

1.ListView 用于展示列表的元素 ListView
2.适配器 ,将数据和容器连接的桥梁
3.数据源 ,具体的数据

1.4 适配器

  适配器是连接数据和容器的桥梁或者通道。通过它能有效的将数据和View实现分离。使得数据的绑定更加的简便。将数据源适配到ListView上的适配器有:ArrayAdapter、SimpleAdapter 和 SimpleCursorAdapter。
● ArrayAdapter最为简单,只能展示一行字;
● SimpleAdapter有最好的扩充性,可以自定义各种各样的布局,除了文本外,还可以放ImageView(图片)、Button(按钮)、CheckBox(复选框)等等;
● SimpleCursorAdapter可以认为是SimpleAdapter对数据库的简单结合,可以方便地把数据库的内容以列表的形式展示出来。
● 但是实际工作中,常用自定义适配器。即继承于BaseAdapter的自定义适配器类。

2. ListView的简单用法

假设你有一组数据需要通过ListView显示在屏幕上,你要怎么做呢?
1.首先需要有一个ListView的控件在layout文件上,用于装载数据.新建一个 activity_mylist.xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:id="@+id/myList_lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

2.既然是要装载数据,哪还得有数据,这个数据可以是从网上下载,也可以是从数据库中读取,具体情况视场景而定,这里写了一个数组data,里面包括了学生的姓名。

    String [] data={"学生一","学生二","学生三","学生四","学生五","学生六","学生七","学生八","学生九","学生十","学生十一","学生十二","学生十三"};

3.有了容器和数据了,我们接下来就需要的是将数据装载到容器里面了。这时候需要用到adapter适配器。 适配器的作用是为了将数组数据一个个的装载到容器里面。Android 中提供了许多适配器的实现类,这里用ArrayAdapter ,通过使用泛型来指定要适配的数据类。这里用的是字符串,所以用String 类,然后在ArrayAdapter的构造函数依次传入当前的上下文对象,ListView 项目的子布局,以及适配的数据。最后将数据装载到容器中

public class MainActivity extends AppCompatActivity {
    String [] data={"学生一","学生二","学生三","学生四","学生五","学生六","学生七","学生八","学生九","学生十","学生十一","学生十二","学生十三"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mylist);
        ListView  listView = (ListView) findViewById(R.id.myList_lv);
        ArrayAdapter<String > adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,data);
        listView.setAdapter(adapter);
    }
}

2.1 使用系统自带布局文件的不同效果

1.android.R.layout.simple_list_item_1
只改一个系统布局还不行, 加上这个 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);


listview数据运行效果

2.android.R.layout.simple_list_item_checked

        ListView listView= (ListView) findViewById(R.id.list3);
        ArrayAdapter<String>  arrayAdapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_checked,data);
        listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        listView.setAdapter(arrayAdapter);
多选

3.android.R.layout.simple_list_item_multiple_choice
只改一个系统布局还不行, 加上这个 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

  ListView listView= (ListView) findViewById(R.id.list3);
        ArrayAdapter<String>  arrayAdapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_multiple_choice,data);
        listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        listView.setAdapter(arrayAdapter);
多选

4.simple_list_item_single_choice

        ListView listView= (ListView) findViewById(R.id.list3);
        ArrayAdapter<String>  arrayAdapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_single_choice,data);
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        listView.setAdapter(arrayAdapter);
单选

3.ListView的一般用法

  在一般的应用中我们可能会加载到图片,实现图文混排的效果。先来张效果图。


图文混排
3.1 方法一:

实践步骤:
1.每个item 的设计都是 图片+文字这样来处理的,所以首先新建一个layout文件设计子项目的布局 item_list.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="100dp"
    android:gravity="center_vertical"
    android:padding="10dp">

    <ImageView
       android:id="@+id/iv_head"
        android:layout_width="80dp"
        android:layout_height="match_parent"
        android:src="@mipmap/ic_launcher"
        android:scaleType="centerCrop"/>
    <TextView
        android:id="@+id/tv_student_name"
        android:layout_width="wrap_content"
        android:layout_height="80dp"
        android:text="学生姓名"
        android:layout_gravity="center"
        android:gravity="center"/>

</LinearLayout>

2.之前说过加载文件资源需要先提供本地资源,再通过adapter来加载资源

public class MainActivity extends AppCompatActivity {
    private ListView listView;
    String [] data={"学生一","学生二","学生三","学生四","学生五","学生六","学生七","学生八","学生九","学生十","学生十一","学生十二","学生十三"};
   private  int [] imagesId={R.mipmap.aa1,R.mipmap.a1,R.mipmap.a2,R.mipmap.a3,R.mipmap.a4,R.mipmap.a5,R.mipmap.a6,R.mipmap.a7,R.mipmap.a8,R.mipmap.a9,R.mipmap.a10,R.mipmap.a11,R.mipmap.a12,R.mipmap.a13};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mylist);
        listView = (ListView) findViewById(R.id.myList_lv);

        BaseAdapter baseAdapter=new BaseAdapter() {
            @Override
            public int getCount() {
                return data.length;
            }

            @Override
            public Object getItem(int position) {
                return null;
            }

            @Override
            public long getItemId(int position) {
                return 0;
            }

            //获取每一行的布局
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {

              //获取行布局
                LayoutInflater inflater = getLayoutInflater();
                LinearLayout layout = (LinearLayout)inflater.inflate(R.layout.item_list, null);

                //行布局中的控件
                ImageView image = (ImageView)layout.findViewById(R.id.iv_head);
                TextView tv1 = (TextView)layout.findViewById(R.id.tv_student_name);
              //更新行布局中的内容
                image.setImageResource(imagesId[position]);
                tv1.setText(data[position]);

                return layout;
            }
        };

listView.setAdapter(baseAdapter);
    }

3.2 方法二:

1.定义一个实体类 Student


public class Student {
    private  String name;
    private  int  imageId;

    public Student(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getImageId() {
        return imageId;
    }

    public void setImageId(int imageId) {
        this.imageId = imageId;
    }
}

2.创建适配器StudentAdapter


public class StudentAdapter  extends ArrayAdapter<Student> {
    private  int resourceId;

    public StudentAdapter(@NonNull Context context, @LayoutRes int resource, List<Student> objects) {
        super(context, resource,objects);
       resourceId=resource;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Student student=getItem(position);
        View view= LayoutInflater.from(getContext()).inflate(resourceId,parent,false);//false 表明我们只让在父布局中的layout生效,但不会为这个View添加父布局(只有孤儿才能被领养)
        ImageView studentImage= (ImageView) view.findViewById(R.id.iv_head);
        TextView  studentname= (TextView) view.findViewById(R.id.tv_student_name);
        studentImage.setImageResource(student.getImageId());
        studentname.setText(student.getName());
        return view;
    }
}

3.加载数据


public class MainActivity2  extends AppCompatActivity {

    private List<Student> studentList=new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mylist);
        initStudent();
        StudentAdapter adapter=new StudentAdapter(MainActivity2.this,R.layout.item_list,studentList);
        ListView listView= (ListView) findViewById(R.id.myList_lv);
        listView.setAdapter(adapter);

    }
//通过循环将数据加载到List<Student>当中
//初始化所有的学生数据,通过构造函数将学生名字和对应的图片添加上去,这里循环两边是为了显示更多的数据,显示一遍也可以。
    private void initStudent() {
        for (int i = 0; i < 2; i++) {
            Student student1=new Student("学生一",R.mipmap.a1);
            studentList.add(student1);
            Student student2=new Student("学生二",R.mipmap.a2);
            studentList.add(student2);
            Student student3=new Student("学生三",R.mipmap.a3);
            studentList.add(student3);
            Student student4=new Student("学生四",R.mipmap.a4);
            studentList.add(student4);
            Student student5=new Student("学生五",R.mipmap.a5);
            studentList.add(student5);
            Student student6=new Student("学生六",R.mipmap.a6);
            studentList.add(student6);
            Student student7=new Student("学生七",R.mipmap.a7);
            studentList.add(student7);
            Student student8=new Student("学生八",R.mipmap.a8);
            studentList.add(student8);
            Student student9=new Student("学生九",R.mipmap.a9);
            studentList.add(student9);
            Student student10=new Student("学生十",R.mipmap.a10);
            studentList.add(student10);
            Student student11=new Student("学生十一",R.mipmap.a11);
            studentList.add(student11);
            Student student12=new Student("学生十二",R.mipmap.a12);
            studentList.add(student12);
            Student student13=new Student("学生十三",R.mipmap.a13);
            studentList.add(student13);

        }
    }

}

4.ListView 的优化

ListView有时会比较难用,有很多细节需要优化。
1.getView()方法中的convertView 参数,这个参数是用于将之前加载好的布局进行缓存,以便之后可以进行重用。修改代码:

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Student student=getItem(position);
        View  view;
        if(convertView==null){
            view= LayoutInflater.from(getContext()).inflate(resourceId,parent,false);//false 表明我们只让在父布局中的layout生效,但不会为这个View添加父布局(只有孤儿才能被领养)
        }else{
            view=convertView;
        }
        ImageView studentImage= (ImageView) view.findViewById(R.id.iv_head);
        TextView  studentname= (TextView) view.findViewById(R.id.tv_student_name);
        studentImage.setImageResource(student.getImageId());
        studentname.setText(student.getName());
        return view;
    }

通过对convertView进行空判断,使用LayoutInflate 去加载布局。不为空就对convertview进行重用,提高了使用效率。在数据量大,快速滚动的时候性能更优异。

2.新增内部类ViewHolder,用于对控件实例化并进行缓存。然后调用setTag()方法,将ViewHolder对象存储在View中。当convertview不为空的时候,调用View的getTag()方法去除ViewHolder对象。


    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Student student=getItem(position);
        View  view;
        ViewHolder  holder;
        if(convertView==null){
            view= LayoutInflater.from(getContext()).inflate(resourceId,parent,false);//false 表明我们只让在父布局中的layout生效,但不会为这个View添加父布局(只有孤儿才能被领养)
           holder=new ViewHolder();
            holder.studentImage=(ImageView) view.findViewById(R.id.iv_head);
            holder.studentname=(TextView) view.findViewById(R.id.tv_student_name);
            view.setTag(holder);//将viewholder 存储在View中

        }else{
            view=convertView;
            holder= (ViewHolder) view.getTag();
        }

        holder.studentImage.setImageResource(student.getImageId());
        holder.studentname.setText(student.getName());
        return view;
    }
    class ViewHolder{
        ImageView studentImage;
        TextView  studentname;
    }

5. ListView的点击事件

如果ListView 只能滚动的话,只满足了视觉上的要求,但是真正的需求是点击事件。只有通过点击选中某个item展示这个item的内容,才是我们所想要的。修改代码:

public class MainActivity2  extends AppCompatActivity {

    private List<Student> studentList=new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mylist);
        initStudent();
        StudentAdapter adapter=new StudentAdapter(MainActivity2.this,R.layout.item_list,studentList);
        ListView listView= (ListView) findViewById(R.id.myList_lv);
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Student student=studentList.get(position);
                Toast.makeText(MainActivity2.this, student.getName(), Toast.LENGTH_SHORT).show();
            }
        });
    }
listview的点击事件

github地址:https://github.com/wangxin3119/myListView

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容