Android之ListView分頁加載數據功能實現

Android之ListView分頁加載數據功能實現

什麼是ListView分頁加載數據功能呢?在現在的大數據時代,我們不可能把某些數據全部展示到界面,好比我們經常會看的QQ空間一樣,當你看動態的時候,系統不可能會把所有好友的動態都展示在上面,你能看到的一般都是最新好友更新的動態,假如你要看非最新的好友動態,通常你都會手指向上滑動屏幕然後去查看,當界面下滑到一定數量的時候,就會看到一個“查看更多”,然後突然停頓一下,系統會通過網絡去給你刷新其他動態信息,這樣的功能我們一般叫做數據下拉刷新功能,也就是我們的分頁加載功能,具體的實現是怎樣的呢?下面我們開始詳細講解。

實現的原理:
1. 首先要先確定默認展示在ListView上的數據,比如默認在ListView上展示10條數據。
2. 將數據傳遞到自定義的適配器上,然後加載到ListView中。
3. 當用戶將數據拉到最後一條的時候,就要開始刷新加載新數據了。
4. 通過監聽ListView的滑動事件,判斷是否達到最後一條,如果達到最後一條則開始刷新。

詳細的實現步奏在代碼中詳細講解。

整體結構如下:

這裏寫圖片描述

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:context="com.company.listviewdeepknow.MainActivity">

    <ListView
        android:id="@+id/mList"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </ListView>
</RelativeLayout>

foot_boot.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="70dp"
    android:gravity="center"
    android:orientation="horizontal">

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleSmall"
        android:layout_width="45dp"
        android:layout_height="45dp" />

    <TextView
        android:id="@+id/mLoad"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="加載更多..."
        android:textSize="20sp" />
</LinearLayout>

list_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="match_parent"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/mTv1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/mTv2"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_alignParentRight="true"
        android:textSize="20sp" />
</RelativeLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements MyOnScrollListener.OnloadDataListener {
    //ListView展示的數據項
    private List<Student> data;
    //ListView控件
    private ListView mList;

    //自定義適配器
    MyAdapter adapter;

    //底部加載更多佈局
    View footer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //首先加載默認數據,這裏設置爲10條
        getData();
        //顯示到ListView上
        showListView(data);
        //自定義的滾動監聽事件
        MyOnScrollListener onScrollListener = new MyOnScrollListener(footer);
        //設置接口回調
        onScrollListener.setOnLoadDataListener(this);
        //設置ListView的滾動監聽事件
        mList.setOnScrollListener(onScrollListener);
    }

    /**
     * 初始化ListView數據,默認設置爲10條
     */
    private void getData() {
        data = new ArrayList<>();
        Student stu = null;
        for (int i = 0; i < 10; i++) {
            stu = new Student();
            stu.setName("姓名" + i);
            stu.setSex(i % 2 == 0 ? "男" : "女");
            data.add(stu);
        }
    }

    /**
     * 將數據加載到ListView上
     *
     * @param data
     */
    private void showListView(List<Student> data) {
        //首先判斷適配器是否爲空,首次運行肯定是爲空的
        if (adapter == null) {
            //查到ListView控件
            mList = (ListView) findViewById(R.id.mList);
            //將底部加載一個加載更多的佈局
            footer = LayoutInflater.from(this).inflate(R.layout.foot_boot, null);
            //初始狀態爲隱藏
            footer.setVisibility(View.GONE);
            //加入到ListView的底部
            mList.addFooterView(footer);
            //創建adpter數據
            adapter = new MyAdapter(data);
            //設置adapter
            mList.setAdapter(adapter);
        } else {
            //不爲空,則刷新數據
            this.data.addAll(data);
            //提醒ListView重新更新數據
            adapter.notifyDataSetChanged();
        }
    }


    @Override
    public void onLoadData(List<Student> data) {
        //加載數據完成後,展示數據到ListView
        showListView(data);
    }
}

MyOnScrollListener.java

public class MyOnScrollListener implements AbsListView.OnScrollListener {

    //ListView總共顯示多少條
    private int totalItemCount;

    //ListView最後的item項
    private int lastItem;

    //用於判斷當前是否在加載
    private boolean isLoading;

    //底部加載更多佈局
    private View footer;

    //接口回調的實例
    private OnloadDataListener listener;

    //數據
    private List<Student> data;

    public MyOnScrollListener(View footer) {
        this.footer = footer;
    }
    //設置接口回調的實例
    public void setOnLoadDataListener(OnloadDataListener listener) {
        this.listener = listener;
    }

    /**
     * 滑動狀態變化
     *
     * @param view
     * @param scrollState 1 SCROLL_STATE_TOUCH_SCROLL是拖動   2 SCROLL_STATE_FLING是慣性滑動  0SCROLL_STATE_IDLE是停止 , 只有當在不同狀態間切換的時候纔會執行
     */
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        //如果數據沒有加載,並且滑動狀態是停止的,而且到達了最後一個item項
        if (!isLoading && lastItem == totalItemCount && scrollState == SCROLL_STATE_IDLE) {
            //顯示加載更多
            footer.setVisibility(View.VISIBLE);
            Handler handler = new Handler();
            //模擬一個延遲兩秒的刷新功能
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (listener != null) {
                        //開始加載更多數據
                        loadMoreData();
                        //回調設置ListView的數據
                        listener.onLoadData(data);
                        //加載完成後操作什麼
                        loadComplete();
                    }
                }
            }, 2000);
        }
    }

    /**
     * 當加載數據完成後,設置加載標誌爲false表示沒有加載數據了
     * 並且設置底部加載更多爲隱藏
     */
    private void loadComplete() {
        isLoading = false;
        footer.setVisibility(View.GONE);

    }

    /**
     * 開始加載更多新數據,這裏每次只更新三條數據
     */
    private void loadMoreData() {
        isLoading = true;
        Student stu = null;
        data = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            stu = new Student();
            stu.setName("新名字" + i);
            stu.setSex("新性別" + i);
            data.add(stu);
        }
    }


    /**
     * 監聽可見界面的情況
     *
     * @param view             ListView
     * @param firstVisibleItem 第一個可見的 item 的索引
     * @param visibleItemCount 可以顯示的 item的條數
     * @param totalItemCount   總共有多少個 item
     */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        //當可見界面的第一個item  +  當前界面多有可見的界面個數就可以得到最後一個item項了
        lastItem = firstVisibleItem + visibleItemCount;
        //總listView的item個數
        this.totalItemCount = totalItemCount;
    }
    //回調接口
    public interface OnloadDataListener {
        void onLoadData(List<Student> data);
    }
}

MyAdapter.java

public class MyAdapter extends MyBaseAdapter<Student> {

    public MyAdapter(List<Student> data) {
        super(data);
    }

    @Override
    public void setData(ViewHolder holder, Student t) {
        holder.setText(R.id.mTv1, t.getName()).setText(R.id.mTv2, t.getSex());

    }

}

MyBaseAdapter.java

public abstract class MyBaseAdapter<T> extends BaseAdapter {
    protected List<T> data;
    public MyBaseAdapter(List<T> data){
        this.data = data;
    }
    @Override
    public int getCount() {
        return data == null ? 0 : data.size();
    }

    @Override
    public Object getItem(int position) {
        return data.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = ViewHolder.getHolder(convertView,parent,position, R.layout.list_item);
        setData(holder,data.get(position));
        return holder.getConvertView();
    }
    public abstract void setData(ViewHolder holder,T t);
}

ViewHolder.java

public class ViewHolder {
    private int position;
    private SparseArray<View> array;
    private View convertView;
    private Context context;

    private ViewHolder(ViewGroup parent, int position, int layout) {
        this.position = position;
        this.context = parent.getContext();
        convertView = LayoutInflater.from(parent.getContext()).inflate(layout, null);
        convertView.setTag(this);
        array = new SparseArray<>();
    }

    public static ViewHolder getHolder(View convertView, ViewGroup parent, int position, int layout) {
        if (convertView == null) {
            return new ViewHolder(parent, position, layout);
        } else {
            ViewHolder holder = (ViewHolder) convertView.getTag();
            holder.position = position;
            return holder;
        }
    }

    public <T extends View> T getView(int viewId) {
        View view = array.get(viewId);
        if (view == null) {
            view = convertView.findViewById(viewId);
            array.put(viewId, view);
        }
        return (T) view;
    }

    public View getConvertView() {
        return convertView;
    }

    public ViewHolder setText(int viewId, String data) {
        TextView tv = getView(viewId);
        tv.setText(data);
        return this;
    } 

Student.java

public class Student {
    private String name;
    private String sex;

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

除了MyAdapter.java MyBaseAdapter.java ViewHolder.java 以及 Student.java實體類沒有註解,其他兩個主要實現類都已經註釋了,關於自定義通用適配器的講解,本篇不做講解,如果想了解如何實現自定義通用適配器知識的可以查看:http://blog.csdn.net/qq_27630169/article/details/52200885

下面可以看看效果圖:

這裏寫圖片描述

發佈了58 篇原創文章 · 獲贊 19 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章