ListView的使用方法(附详解+源码)

效果图

请添加图片描述

代码部分

ListViewActivity(显示ListView的Activity)

package com.gaojc.activity;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import com.gaojc.adapter.MyAdapter;
import com.gaojc.data.MyData;
import com.gaojc.text.R;
import java.util.ArrayList;

public class ListViewActivity extends Activity {

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

        ListView myListView = findViewById(R.id.myListView);
        // 创建数据源
        ArrayList<MyData> myData = new ArrayList<>();
        // 适配器类(用来给ListView填充数据)
        MyAdapter myAdapter = new MyAdapter(ListViewActivity.this,myData);

        /**
         * 添加假数据
         */
        for (int i = 0; i < 15; i++) {
            myAdapter.add(new MyData(0.1 + i + "",10 + i + "%"));
        }

        // 设置创建生成的数据适配器
        myListView.setAdapter(myAdapter);
    }
}

相对应的xml文件(activity_list_view.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="com.gaojc.activity.ListViewActivity"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="ListView示例"
        android:gravity="center"
        android:textSize="30dp"/>

    <ListView
        android:id="@+id/myListView"
        android:layout_width="300dp"
        android:layout_height="450dp"
        android:layout_gravity="center"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="15dp"
        android:paddingBottom="20dp"
        android:divider="@null"
        android:dividerHeight="5dp"
        android:background="@drawable/every_day_get_money_bg1"/>

</FrameLayout>

ListView属性介绍

android:divider="@null" :不显示分割线
android:dividerHeight="5dp" :指定分割线的高
android:scrollbars="none" :隐藏滚动条

MyData数据源

package com.gaojc.data;

public class MyData {

    public String money; //显示金额
    public String ratio; //比例

    public MyData(String money, String ratio) {
        this.money = money;
        this.ratio = ratio;
    }

    public String getRatio() {
        return ratio;
    }
}

MyAdapter适配器类

package com.gaojc.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.gaojc.data.MyData;
import com.gaojc.text.R;
import com.gaojc.text.Utils.LogUtil;
import java.util.ArrayList;

/**
 * 适配器类(用来给ListView填充数据)
 *      需要继承 BaseAdapter
 */
public class MyAdapter extends BaseAdapter {

    public Context context;
    public ArrayList<MyData> myData;

    public MyAdapter(Context context, ArrayList<MyData> myData) {
        this.context = context;
        this.myData = myData;
    }

    /**
     * @return:要绑定的条目的数目(格子的数量)
     */
    @Override
    public int getCount() {
        return myData.size();
    }

    /**
     * 根据索引(位置)获得该位置的对象
     * @param i:索引
     * @return:获取该位置的对象
     */
    @Override
    public MyData getItem(int i) {
        // 这里的返回类型改为自己的数据类
        return myData.get(i);
    }

    /**
     * @return: 返回条目的id
     */
    @Override
    public long getItemId(int i) {
        return i;
    }

    /**
     * 获取该条目要显示的界面
     * @param i:当前条目
     * @param convertView:绘制好的视图
     * @param viewGroup:对应的xml文件(单个条目 list_view_adapter.xml)
     * @return
     */
    @Override
    public View getView(int i, View convertView, ViewGroup viewGroup) {
        MyData myData = getItem(i); //获取当前位置的对象
        View view;
        ViewHolder viewHolder;
        if (convertView == null) {
            // 把xml布局文件解析成View
            view = LayoutInflater.from(context).inflate(R.layout.list_view_adapter, viewGroup, false);
            // 添加数据  setTag:监听相对应的事件
            viewHolder = new ViewHolder();
            viewHolder.textMoney = view.findViewById(R.id.textMoney);
            viewHolder.textMoneyTwo = view.findViewById(R.id.textMoneyTwo);
            viewHolder.listViewProBar = view.findViewById(R.id.listViewProBar);
            viewHolder.ratio = view.findViewById(R.id.ratio);
            viewHolder.getButton = view.findViewById(R.id.getButton);
            view.setTag(viewHolder);
        } else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag(); //重新获取ViewHolder
        }

        viewHolder.getButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                LogUtil.e("点击了领取按钮");
                // 获取比例
                String ratio = myData.getRatio();
                LogUtil.e("比例是:" + ratio);
                if (ratio.equals("100%")) {
                    Toast.makeText(context, "可以提现", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(context, "不能提现", Toast.LENGTH_SHORT).show();
                }
            }
        });

        // 设置各节点内容
        viewHolder.textMoney.setText(myData.money + "元");
        viewHolder.textMoneyTwo.setText(myData.money + "元奖励进度");
        String ratio = myData.ratio.replace("%", "");
        viewHolder.listViewProBar.setProgress(Integer.parseInt(ratio));
        viewHolder.ratio.setText(myData.ratio);

        return view;
    }

    // 需要的数据
    private class ViewHolder {
        TextView textMoney; //红包金额
        TextView textMoneyTwo; //金额奖励进度
        ProgressBar listViewProBar; //进度比例
        TextView ratio; //显示的进度比例数
        Button getButton; //领取按钮
    }

    // 添加数据方法
    public void add(MyData data){
        if (myData == null){
            myData = new ArrayList<>();
        }
        myData.add(data);
    }
}

单个View条目xml(list_view_adapter.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="60dp"
    android:background="@drawable/every_day_get_money_listview_item_background">
    
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="2.5"
            android:background="@drawable/red_package"/>
        <TextView
            android:id="@+id/textMoney"
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:text="0.3元"
            android:background="@drawable/red_package_2"
            android:gravity="center"
            android:textColor="#FF0000"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3"
        android:orientation="vertical">
        <TextView
            android:id="@+id/textMoneyTwo"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:text="0.3元奖励进度"
            android:gravity="center"/>
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:layout_marginBottom="5dp">
            <ProgressBar
                android:id="@+id/listViewProBar"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/progress_bg"
                android:progress="60"
                android:progressDrawable="@drawable/storage_bar" />
            <TextView
                android:id="@+id/ratio"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="60%"
                android:gravity="center"
                android:textColor="#FFFFFF"/>
        </FrameLayout>
    </LinearLayout>

    <Button
        android:id="@+id/getButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1.1"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:background="@drawable/receive"/>

</LinearLayout>

加载进度所需要的进度条(storage_bar.xml)

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--    绿色进度条-->
    <item
        android:id="@android:id/progress">
        <scale
            android:scaleWidth="100%">
            <shape>
                <corners android:radius="15dip"/>
                <solid android:color="#66CC08"/>
            </shape>
        </scale>

    </item>
</layer-list>

下载项目源码

如何优化ListView?

优化ListView(或者其他类似的列表组件,如RecyclerView等)的性能是移动应用开发中常见的需求,尤其在处理大量数据或复杂项布局时。以下是一些优化ListView性能的策略:

  • 复用视图(View Holder模式):通过Adapter的getView()方法(对于RecyclerView则是onCreateViewHolder()和onBindViewHolder())实现视图复用。创建一个视图持有者(View Holder)类来缓存每个列表项的子视图引用,减少每次滚动时查找子视图的开销。
  • 异步加载数据和图片:对于网络图片或耗时的数据获取操作,使用异步加载技术,如AsyncTask(Android旧版本,已废弃,推荐使用Kotlin协程、ExecutorService或第三方库如Glide、Picasso等)来避免阻塞UI线程。
  • 分页加载:不一次性加载所有数据,而是采用分页加载的方式,只加载当前显示区域及附近的数据,当用户滚动到列表底部时再加载更多数据。
  • ViewHolder池技术:在极高的滚动速度下,即使使用了ViewHolder,频繁的创建和销毁ViewHolder也可能成为瓶颈。可以通过实现一个ViewHolder池来重用已经初始化过的ViewHolder对象,进一步减少对象创建和销毁的开销。
  • 减少布局层级和优化布局:确保每个列表项的布局尽可能简洁,减少嵌套,使用轻量级的View组件。可以考虑使用、标签优化布局结构。
  • 启用硬件加速:如果你的应用目标API级别支持,确保硬件加速功能已开启,这可以提高图形绘制的性能。
  • 合理设置ListView的高度:对于ListView,如果内容高度可预知,设置固定高度可以避免ListView在滚动时重复测量子View,从而提升性能。
  • 避免过度绘制:使用开发者工具检查并减少界面的过度绘制,确保每个像素点只被绘制一次。
  • 使用性能更优的列表组件:对于Android开发,推荐使用RecyclerView替代ListView,RecyclerView提供了更多的灵活性和性能优化选项,比如item动画、ViewType等。
  • 监听滑动状态进行适当优化:利用OnScrollListener或RecyclerView.OnScrollListener监听滑动状态,当列表停止滑动时再执行耗时操作,避免影响滑动流畅性。

ListView 和 RecyclerView的区别?

ListView和RecyclerView都是Android中用于展示列表数据的组件,但它们之间存在一些显著的区别:

  • 灵活性:RecyclerView提供了更高的灵活性和定制性。它允许你通过不同的LayoutManager(如LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager)来改变列表的布局方式,不仅限于垂直滚动,还可以实现网格视图、瀑布流等布局;而ListView 只支持单一的线性垂直布局。
  • 性能优化:RecyclerView相比ListView具有更好的性能。RecyclerView内部实现了ViewHolder模式,这减少了查找View的次数,提高了滚动时的效率。此外,RecyclerView拥有更精细的缓存机制,分为四级缓存(包括mActiveViews、mCachedViews、mAttachedScrap和通过RecycledViewPool实现的跨Adapter缓存),这有助于提高视图重用率,减少内存消耗和CPU使用,使得处理大量数据时表现更流畅。
  • 滚动效果与动画:RecyclerView更容易实现复杂的滚动效果和条目动画,因为它提供了更多的回调方法和动画支持;而 ListView 需要手动实现这些功能。ListView 不支持嵌套滚动,而 RecyclerView 支持嵌套滚动。这意味着您可以将 RecyclerView 嵌套在另一个可滚动视图中,例如 ScrollView 或 ViewPager。
  • API设计与使用便捷性:RecyclerView 通过使用 RecyclerView.Adapter 和 ViewHolder 的组合来实现视图的重用机制,使得滚动流畅。它会根据视图的可见性动态地创建和重用 ViewHolder,以避免频繁地创建和销毁视图。而 ListView 通过 ArrayAdapter 或 BaseAdapter,没有明确的 ViewHolder 概念。
  • 内存管理:RecyclerView的四级缓存系统使其在内存管理上更为高效,尤其是在数据集变化频繁或数据量大时,能更有效地重用和管理视图。

总结来说,RecyclerView 在灵活性、重用机制、动画和交互、性能优化等方面都比 ListView 更强大和灵活。因此,在新的项目中建议使用RecyclerView 替代 ListView。然而,如果仅需简单的线性垂直列表,或者需要与过时的 API 兼容,使用 ListView 也是可以的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是阿超

现在二师兄的肉比师父的都贵了.

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值