ListView 分页的实现

前言:众所周知ListView这个控件是安卓中常用而又难用的控件,其分页功能也是我们在app中常见的功能,本篇详细讲解其分页的实现(建议对listview的adapter有些了解,以及java基础的面向对象及接口的实现类有些了解的在看本篇)。

一 首先看下篇章结构:


image.png

(为了逻辑清晰 方便阅读)

二 基本思路实现(后面附代码及详细注释)
1 activity_main.xml中创建ListView(此处先建立ListView)
2 MainActivity中先实现ListView要展示的界面(效果如下)

image.png

其中QQ为javaBean封装的字段(就封装这一个字段)
图片 按钮 直接是通过adapter加载xml视图填充的

3 实现了上面的布局后修改ListView :
自定义类(LoadFootListView )继承ListView 实现主要方法(添加底部布局View)
然后把前面的ListView修改为自定义的ListView
4 自定义类中滑动事件的监听实现 自定义类中调用MainActivity中数据(接口的回调)

三 代码实现
1 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.administrator.listviewdividepage.MainActivity">
      <com.example.administrator.listviewdividepage.LoadFootListView
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:id="@+id/lv_list">
      </com.example.administrator.listviewdividepage.LoadFootListView>

</LinearLayout>

2 MainActivity

package com.example.administrator.listviewdividepage;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;


import com.example.administrator.listviewdividepage.Adapters.MyListViewBaseAdapter;
import com.example.administrator.listviewdividepage.JavaBeans.QQDesc;

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


public class MainActivity extends AppCompatActivity implements LoadFootListView.ILoadListener {

    private LoadFootListView lvList;//listview 控件
    private List<QQDesc> qqList;//集合
    private MyListViewBaseAdapter adapter = null;//数据适配器

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        qqList = new ArrayList<QQDesc>();// 初始化集合
        initListView();
    }

    private void initListView() {
        // 先在集合中加入6条数据
        for (int i = 0; i < 6; i++) {
            QQDesc qqDesc = new QQDesc();
            qqDesc.setName("QQ");
            qqList.add(qqDesc);
        }
        if (adapter == null) {
            lvList = (LoadFootListView) findViewById(R.id.lv_list);
            lvList.setInterface(this);
            adapter = new MyListViewBaseAdapter(this, qqList);
            lvList.setAdapter(adapter);
        } else {
            adapter.notifyDataSetChanged();
        }
    }

    /* 接口的方法  */
    @Override
    public void onLoad() {
        //1加载更多数据  通知listView显示数据

         // 为了能看见效果个两秒后加载数据
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 2; i++) {
                    QQDesc qqDesc = new QQDesc();
                    qqDesc.setName("QQ");
                    qqList.add(qqDesc);
                }
                if (adapter == null) {
                    lvList = (LoadFootListView) findViewById(R.id.lv_list);
                    lvList.setInterface(MainActivity.this);
                    adapter = new MyListViewBaseAdapter(MainActivity.this, qqList);
                    lvList.setAdapter(adapter);
                } else {
                    adapter.notifyDataSetChanged();
                    lvList.lodaComplete();// 加载完毕隐藏view
                }
            }
        },2000);
        
}
};

3 自定义ListView(LoadFootListView)

package com.example.administrator.listviewdividepage;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;

/**
 * Created by Administrator on 2017/11/28.
 * 自定义ListView 实现底部分页加载
 * 1 吧底部加载的布局View加入listView
 * 2 滑动事件的监听(listView实现滑动监听接口)
 */
public class LoadFootListView extends ListView implements AbsListView.OnScrollListener{

    private int  totalItemCount;//当前总条目
    private int lastVisibleItem;//最后一个可见条目
    private View mView;//底部布局的View
    private boolean isLoading=false;//加载判断
    private ILoadListener iLoadListener;//接口实现类

    public LoadFootListView(Context context) {
        super(context);
        initFootLoad(context);
    }

    public LoadFootListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initFootLoad(context);
    }

    public LoadFootListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initFootLoad(context);
    }
        // 初始化分页加载
     public void initFootLoad(Context context){
         mView = View.inflate(context, R.layout.foot_item,null);
         // 吧定义好的view 放入listView底部
         this.addFooterView(mView);
         // 设置滚动事件的监听
         this.setOnScrollListener(this);
         // 初始的时候隐藏
         mView.findViewById(R.id.load_more).setVisibility(View.GONE);

     }

    /* 接口的两个滑动方法*/
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // 进行底部判断  (划到底部 切停止滑动)
        if(lastVisibleItem==totalItemCount&&scrollState==SCROLL_STATE_IDLE){
            // 加载更多新的数据(MainActivity中的数据)
            // 加载数据之前进行显示加载布局
            if(!isLoading){
                isLoading = true;
                mView.findViewById(R.id.load_more).setVisibility(View.VISIBLE);
                //加载更多(加载MainActivity中的数据 接口回调)
                iLoadListener.onLoad();//接口实现类加载函数实先 方法
            }


        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        /* 最后一个可见的条目为: 第一个可见的+ 可见的条目个数*/
        this.lastVisibleItem = firstVisibleItem+visibleItemCount;
        /* 滑到底部的时候的值*/
        this.totalItemCount=totalItemCount;
        //通过以上两个值判断是否滑到底部
    }
    /* 加载更多数据的回调接口
    * 在其他的类中实现就行了 本类中使用接口(设置接口使用函数)
    * */
    public void setInterface(ILoadListener iLoadListener){
        //通过外面的接口实现类调用此函数  传进来实现类对象
        this.iLoadListener=iLoadListener;
    }
    public interface ILoadListener{
     public void onLoad();
    }
    public void lodaComplete(){
        isLoading=false;
        mView.findViewById(R.id.load_more).setVisibility(View.GONE);
    }
}

4 adapter的实现(MyListViewBaseAdapter)

package com.example.administrator.listviewdividepage.Adapters;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.example.administrator.listviewdividepage.JavaBeans.QQDesc;
import com.example.administrator.listviewdividepage.R;

import java.util.List;
import java.util.Objects;

/**
 * Created by Administrator on 2017/11/28.
 */

public class MyListViewBaseAdapter extends BaseAdapter {
    /* 由于下面需要 上下文 集合 故在此处声明*/
    private Context context;
    private List<QQDesc>qqList;
    public MyListViewBaseAdapter(Context context,List<QQDesc>qqList){
        this.context= context;
        this.qqList=qqList;
    }
    @Override
    public int getCount() {
        return qqList.size();
    }
    @Override
    public QQDesc getItem(int position) {
        return qqList.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
       /* 简单的优化*/
        View view = null;
        if (convertView==null){
            view = View.inflate(context, R.layout.myadapter_item,null);
            TextView tvName= (TextView) view.findViewById(R.id.tv_name);
            tvName.setText(qqList.get(position).getName());
        }else{
            view=convertView;
        }
        return view;
    }
}

5 java bean

package com.example.administrator.listviewdividepage.JavaBeans;

/**
 * Created by Administrator on 2017/11/28.
 */

public class QQDesc {
     private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}

6 foot_item

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dp"
    android:gravity="center"
    android:id="@+id/load_more">
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:textSize="20sp"
        android:textColor="@color/colorAccent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Loading..."/>

</LinearLayout>

7 listView的布局页面(adapter填充)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/qq"/>
    </LinearLayout>
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/tv_name"
            android:layout_gravity="center"
            android:textSize="20sp"
            android:textColor="@color/colorAccent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="名字"/>
       <Button
           android:id="@+id/btn_download"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="立刻下载"/>
    </LinearLayout>

</LinearLayout>

效果:

image.png

由于过程比较繁琐建议看不懂的吧代码全部粘贴自己建立工程分析代码(有详细注释)

小结:难点在于滑动到底部的判断以及接口的回调。

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

推荐阅读更多精彩内容