Android中的ListView

本文详细介绍了Android中的ListView及其三种适配器ArrayAdapter、SimpleAdapter和BaseAdapter的使用方法。通过示例代码展示了如何设置布局、数据源以及实现点击事件监听,同时讨论了ViewHolder优化技巧以提高性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 ListView概述

下面看一下ListView的应用场景:
在这里插入图片描述


2 适配器

先看下适配器的使用步骤:

  1. 准备布局(每一项的显示效果)
  2. 准备数据源
  3. 实例化适配器(布局+数据源)
  4. 为ListView设置适配器

2.1 ArrayAdapter

效果如下:
在这里插入图片描述
代码也十分简单:

package com.example.listviewdemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

/**
 * 1.准备布局(每一项的显示效果)
 * 2.准备数据源
 * 3.实例化适配器(布局+数据源)
 * 4.为ListView设置适配器
 */
public class ArrayActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_array);

        ListView listView1 = findViewById(R.id.list_view1);

        //参数1:环境上下文(this)
        //参数2:代表数据项所应用的布局
        //参数3:数据源(数组)
        String[] data = {"AA","BB","CC","DD","EE","FF","GG","AA","BB","CC","DD","EE","FF","GG","AA","BB","CC","DD","EE","FF","GG","AA","BB","CC","DD","EE","FF","GG"};

        //使用自定义资源
        ArrayAdapter adapter = new ArrayAdapter(this,R.layout.item2,R.id.txt1,data);

        listView1.setAdapter(adapter);
    }
}

2.2 SimpleAdapter

先看下要实现的效果:
在这里插入图片描述
首先我们要自定义列表显示的layout:

<?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/qq_img"
        android:layout_width="50dp"
        android:layout_height="65dp"
        android:background="@mipmap/caocao"/>

    <TextView
        android:id="@+id/qq_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/qq_img"
        android:textSize="26sp"
        android:text="曹操"/>

    <TextView
        android:id="@+id/qq_mood"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/qq_img"
        android:layout_below="@id/qq_name"
        android:textColor="#00ffff"
        android:text="测试数据"/>
</RelativeLayout>

然后定义Activity对应的Layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SimpleActivity">
    <ListView
        android:id="@+id/list_view2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>
</androidx.constraintlayout.widget.ConstraintLayout>

然后看下Java代码:

package com.example.listviewdemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SimpleActivity extends AppCompatActivity {

    private List<Map<String,Object>> data = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple);

        //获取ListView对象
        ListView listView2 = findViewById(R.id.list_view2);

        //实例化适配器对象
        //参数1:this
        //参数2:数据源
        initData();
        //参数3:每一项布局
        //参数4:数据来源的key数组
        String[] from = {"img","name","mood"};
        //参数5:数据去向的id数组
        int[] to = {R.id.qq_img,R.id.qq_name,R.id.qq_mood};
        //参数45对应索引上,from数组的元素代码数据源每个map的key,该key所指代的数据
        //会作为to数组对应索引上id所代表的控件的内容显示处理
        SimpleAdapter adapter = new SimpleAdapter(this,data,R.layout.item3,from,to);

        //为ListView设置适配器
        listView2.setAdapter(adapter);

        //点击事件
        listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                //用Toast提示Name  Mood
                Map<String,Object> map = data.get(i);
                String name = map.get("name").toString();
                String mood = map.get("mood").toString();
                Toast.makeText(SimpleActivity.this,name+"   "+mood,Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void initData(){
        //左边:头像   右上:名字   右下:心情
        Map<String,Object> map1 = new HashMap<>();
        map1.put("img",R.mipmap.caocao);
        map1.put("name","曹操");
        map1.put("mood","宁教我负天下人,休教天下人负我");

        Map<String,Object> map2 = new HashMap<>();
        map2.put("img",R.mipmap.zhenji);
        map2.put("name","甄姬");
        map2.put("mood","飘摇兮若流风之回雪,仿佛兮若轻云之蔽月");

        Map<String,Object> map3 = new HashMap<>();
        map3.put("img",R.mipmap.simayi);
        map3.put("name","司马懿");
        map3.put("mood","无奈天命之子");

        Map<String,Object> map4 = new HashMap<>();
        map4.put("img",R.mipmap.guojia);
        map4.put("name","郭嘉");
        map4.put("mood","哦");

        Map<String,Object> map5 = new HashMap<>();
        map5.put("img",R.mipmap.caocao);
        map5.put("name","曹操");
        map5.put("mood","宁教我负天下人,休教天下人负我");

        Map<String,Object> map6 = new HashMap<>();
        map6.put("img",R.mipmap.zhenji);
        map6.put("name","甄姬");
        map6.put("mood","飘摇兮若流风之回雪,仿佛兮若轻云之蔽月");

        Map<String,Object> map7 = new HashMap<>();
        map7.put("img",R.mipmap.simayi);
        map7.put("name","司马懿");
        map7.put("mood","无奈天命之子");

        Map<String,Object> map8 = new HashMap<>();
        map8.put("img",R.mipmap.guojia);
        map8.put("name","郭嘉");
        map8.put("mood","哦");


        data.add(map1);
        data.add(map2);
        data.add(map3);
        data.add(map4);
        data.add(map5);
        data.add(map6);
        data.add(map7);
        data.add(map8);
    }
}

2.3 BaseAdapter

下面先看下要实现的效果:
在这里插入图片描述
首先看下主页面的xml文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    tools:context=".BaseActivity">
    <ListView
        android:id="@+id/list_view3"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>

    <ImageView
        android:id="@+id/write"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@mipmap/write"
        android:layout_gravity="right|bottom"
        android:layout_margin="40dp"/>
</FrameLayout>

然后看下item的xml文件:

<?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/profile"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@mipmap/profile1"
        android:layout_margin="5dp"/>

    <TextView
        android:id="@+id/nickname"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:text="用户1"
        android:textSize="26sp"
        android:layout_toRightOf="@id/profile"
        android:layout_marginTop="5dp"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:text="2048-10-24"
        android:textSize="22sp"
        android:layout_toRightOf="@id/profile"
        android:layout_below="@id/nickname"/>

    <TextView
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="啊,多么有意义的日子呀!!"
        android:textSize="22sp"
        android:layout_below="@id/profile"/>

    <ImageView
        android:id="@+id/repost"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:src="@mipmap/repost"
        android:layout_below="@id/content"
        android:layout_alignParentRight="true"
        android:layout_marginRight="10dp"/>

    <ImageView
        android:id="@+id/comment"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:src="@mipmap/comment"
        android:layout_below="@id/content"
       android:layout_toLeftOf="@id/repost"
        android:layout_marginRight="10dp"/>

    <ImageView
        android:id="@+id/like"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:src="@mipmap/like"
        android:layout_below="@id/content"
        android:layout_toLeftOf="@id/comment"
        android:layout_marginRight="10dp"/>
</RelativeLayout>

这里我们需要定义一个实体类,实体类如下:

package com.example.listviewdemo;

public class Msg {
    private int profile;
    private String nickname;
    private String content;
    private boolean isLike;

    public int getProfile() {
        return profile;
    }

    public void setProfile(int profile) {
        this.profile = profile;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public boolean isLike() {
        return isLike;
    }

    public void setLike(boolean like) {
        isLike = like;
    }

    public Msg(int profile, String nickname, String content, boolean isLike) {
        this.profile = profile;
        this.nickname = nickname;
        this.content = content;
        this.isLike = isLike;
    }
}

然后我们需要定义自己的Adapter类:

package com.example.listviewdemo;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

//根据准备好的数据源和子项布局完成ListView效果的一一设置
//做出一些细节处理
public class MyAdapter extends BaseAdapter {
    private List<Msg> list;
    private Context ctx;

    public MyAdapter(List<Msg> list, Context ctx){
        this.list = list;
        this.ctx = ctx;
    }

    //获取数量(设置ListView的长度)
    @Override
    public int getCount() {
        return list.size();
    }

    //获取视图(设置ListView每一项的显示效果)--每个视图出现时都会执行
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        //完成对view的设置
        //将布局资源转为View
        //参数1:你所要引用的布局资源
        //RecycleBin
        ViewHolder holder;
        if(view == null) {
            Log.e("TAG", "======" + i);
            //优化1:利用进入RecycleBin中的View,减少读view的赋值 (数据项看不到时相关视图就会进入RecycleBin中)
            view = LayoutInflater.from(ctx).inflate(R.layout.item4, null);
            holder = new ViewHolder();
            holder.profile = view.findViewById(R.id.profile);
            holder.nickname = view.findViewById(R.id.nickname);
            holder.content = view.findViewById(R.id.content);
            holder.like = view.findViewById(R.id.like);
            holder.comment = view.findViewById(R.id.comment);
            holder.repost = view.findViewById(R.id.repost);
            view.setTag(holder);
        }else{
            //通过getTag()取出ViewHolder对象,然后能过直接通过holder.控件的方式在外面直接操作控件
            //从而避免了大幅度使用findViewById操作
            //而事实上,getTag()本身操作效率高
            holder = (ViewHolder) view.getTag();
        }
        Msg m = list.get(i);

        //头像
//        ImageView profile = view.findViewById(R.id.profile);
        holder.profile.setImageResource(m.getProfile());

        //昵称
//        TextView nickname = view.findViewById(R.id.nickname);
        holder.nickname.setText(m.getNickname());

        //内容
//        TextView content = view.findViewById(R.id.content);
        holder.content.setText(m.getContent());

        //是否点赞
//        ImageView like = view.findViewById(R.id.like);
        if(m.isLike()){
            holder.like.setImageResource(R.mipmap.liked);
        }else{
            holder.like.setImageResource(R.mipmap.like);
        }

        //评论
//        ImageView comment = view.findViewById(R.id.comment);
        holder.comment.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(ctx,"你点击了评论",Toast.LENGTH_SHORT).show();
            }
        });
        //转发
//        ImageView repost = view.findViewById(R.id.repost);
        holder.repost.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(ctx,"--------转发----------",Toast.LENGTH_SHORT).show();
            }
        });
        return view;
    }

    //==============================================酱油方法
    //获取子项
    @Override
    public Object getItem(int i) {
        return null;
    }

    //获取子项id
    @Override
    public long getItemId(int i) {
        return 0;
    }

    //1.自定义一个类,叫做ViewHolder
    //2.将需要保存的视图声明为公开的属性
    //3.什么时候保存?当view为null时,完成对ViewHolder的实例化工作,并为各个控件属性赋值
    //4.什么时候用?  什么时候都要用(性能的提升是在view不为null时体现,滚动ListView时体现)
    //5.怎么用?当view为null时,完成了ViewHolder及内部控件属性的初始化工作后,调用一句代码
    //view.setTag(holder);
    //当view不为null时,holder = view.getTag();
    static class ViewHolder{
        public ImageView profile,like,comment,repost;
        public TextView nickname,content;
    }
}

接下来看下最后的Activity:

package com.example.listviewdemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

public class BaseActivity extends AppCompatActivity {
    private ListView listView3;
    private ImageView write;
    private List<Msg> list = new ArrayList<>();
    private int[] ps = {R.mipmap.profile1,R.mipmap.profile2,
            R.mipmap.profile3,R.mipmap.profile4,R.mipmap.profile5,R.mipmap.profile6,
            R.mipmap.profile7,R.mipmap.profile8};
    private BaseAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base);

        listView3 = findViewById(R.id.list_view3);
        write = findViewById(R.id.write);

        initData();

        //需要传的参数:环境,数据源
        adapter = new MyAdapter(list,this);

        //设置适配器
        listView3.setAdapter(adapter);

        write.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Msg m = new Msg(R.mipmap.profile9,"paradox","这是动态新增的说说",false);
                list.add(m);
                //通知适配器更新数据
                adapter.notifyDataSetChanged();
                //设置listview自动显示到最新数据
                listView3.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
            }
        });
    }

    private void initData() {
        for(int i = 1 ; i <= 8 ; i++){
            Msg m = new Msg(ps[i-1],"用户"+i,"今天天气好晴朗,慕课处处好风光"+i,i%2==0?true:false);
            list.add(m);
        }
    }
}

我们可以看到在ListView中进行了2个优化。ViewHolder通常出现在适配器里,为的是listview滚动的时候快速设置值,而不必每次都重新创建很多对象,从而提升性能。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值