自定義Recyclerview實(shí)現(xiàn)上拉加載

android提供了下拉刷新控件SwipeRefreshLayout正卧,并沒(méi)有提供上拉加載控件缭贡,Recyclerview又并不像Listview一樣提供addHead,addFoot接口,只能通過(guò)自定義實(shí)現(xiàn)向挖。本文實(shí)現(xiàn)了Item相同時(shí)recyclerview的上拉加載功能蚕甥。

1526974666967[1].gif

首先定義一個(gè)基類adapter哪替,代碼里注釋寫的很清楚了

public abstract class BaseRecycleAdapter<T> extends RecyclerView.Adapter<BaseRecycleAdapter.BaseHolder> {

    public List<T> mDatas;

    private final Context mContext;

    private static final int TYPE_ITEM = 0;       //普通Item View
    private static final int TYPE_FOOTER = 1;    //底部FootView

    public static final int PULL_UP_LOAD_MORE = 0;  //上拉加載
    public static final int LOADING_MORE = 1;      //正在加載中
    public static final int NO_MORE_DATA = 2;     //加載完成沒(méi)有數(shù)據(jù)

    private int load_more_status = 0;               //上拉加載狀態(tài)默認(rèn)0
    private OnItemClickListener onItemClickListener;

    public BaseRecycleAdapter(Context context) {
        mContext = context;
    }

    /**
     * 設(shè)置數(shù)據(jù)源 泛型T代表list的泛型
     * @param datas
     */
    public void setData(List<T> datas) {
        mDatas = datas;
    }

    /**
     * item點(diǎn)擊事件
     * @param onItemClickListener
     */
    public void setOnItemClickListener(OnItemClickListener  onItemClickListener){
        this.onItemClickListener = onItemClickListener;
    }

    /**
     * 根據(jù)不同的viewType創(chuàng)建不同的holder
     * @param parent
     * @param viewType
     * @return
     */
    @Override
    public BaseHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        BaseHolder holder = null;
        View view = null;
        if (viewType == TYPE_ITEM) {
            view = LayoutInflater.from(mContext).inflate(getLayoutId(viewType), parent, false);
        } else {
            view = LayoutInflater.from(mContext).inflate(R.layout.pull_load_more, parent, false);
        }
        holder = new BaseHolder(view);
        return holder;
    }


    @Override
    public void onBindViewHolder(BaseHolder holder, final int position) {

        //底部Item 根據(jù)傳入的狀態(tài)更改布局(load_more_status)

        if (holder.getItemViewType() == BaseRecycleAdapter.TYPE_FOOTER) {
            ProgressBar progressBar = (ProgressBar) holder.getView(R.id.progressBar);
            TextView tv_progress_text = (TextView) holder.getView(R.id.tv_progress_text);
            switch (load_more_status){
                case LOADING_MORE:
                    tv_progress_text.setText("正在加載數(shù)據(jù)");
                    progressBar.setVisibility(View.VISIBLE);
                    break;
                case PULL_UP_LOAD_MORE:
                    if (getItemCount()<10){
                        progressBar.setVisibility(View.INVISIBLE);
                        tv_progress_text.setText("");
                    }else {
                        tv_progress_text.setText("上拉加載更多");
                        progressBar.setVisibility(View.INVISIBLE);
                    }
                    break;
                case NO_MORE_DATA:
                    tv_progress_text.setText("沒(méi)有更多數(shù)據(jù)了");
                    progressBar.setVisibility(View.INVISIBLE);
                    break;
            }
        }

        //普通Item 綁定數(shù)據(jù)
        if (holder.getItemViewType() == BaseRecycleAdapter.TYPE_ITEM) {
            onBindData(holder, position, mDatas);
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (onItemClickListener!=null){
                        onItemClickListener.onItemClick(position,v);
                    }
                }
            });
        }
    }

    /**
     * 獲取item數(shù)量
     * @return
     */
    @Override
    public int getItemCount() {
            return mDatas == null ? 0 : mDatas.size() + 1;
    }

    /**
     * 獲取item類型(普通item 、底部item)
     * @param position
     * @return
     */
    @Override
    public int getItemViewType(int position) {
        if (mDatas == null)
            return TYPE_ITEM;
        if (position + 1 == getItemCount()) {
            return TYPE_FOOTER;
        } else {
            return TYPE_ITEM;
        }
    }

    /**
     * 根據(jù)傳入status改變foot狀態(tài)并刷新數(shù)據(jù)
     * @param status
     */
    public void changeMoreStatus(int status) {
        load_more_status = status;
        notifyDataSetChanged();
    }

    /**
     * 根據(jù)type 返回不同的布局
     *
     * @param type
     * @return
     */
    public abstract int getLayoutId(int type);

    /**
     * 綁定數(shù)據(jù)(做成抽象 在子類實(shí)現(xiàn))
     * @param holder
     * @param position
     * @param mDataList
     */
    public abstract void onBindData(BaseHolder holder, int position, List<T> mDataList);

    public static class BaseHolder extends RecyclerView.ViewHolder {
        private Map<Integer, View> mViewMap;
        public View mView;

        public BaseHolder(View itemView) {
            super(itemView);
            mView = itemView;
            mViewMap = new HashMap<>();
        }

        public View getView(int id) {
            View view = mViewMap.get(id);
            if (view == null) {
                view = mView.findViewById(id);
                mViewMap.put(id, view);
            }
            return view;
        }
    }


}

自定義Recyclerview

package com.wckj.myrecyclerview;

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;

import com.wckj.myrecyclerview.Test.BaseRecycleAdapter;

/**
 * Created by HQL
 * on 2018/5/21 0021.
 */

public class MyRecyclerView extends RecyclerView {

    private BaseRecycleAdapter myLoadMoreAdapter;
    OnloadListener mOnLoadListener = null;
    private boolean haveData = true;

    public MyRecyclerView(Context context) {
        this(context,null);
    }

    public MyRecyclerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setOnScrollListener(null);
    }

    @Override
    public void setOnScrollListener(OnScrollListener listener) {
        LoadMoreDataListener loadMoreListener = new LoadMoreDataListener(listener);
        super.setOnScrollListener(loadMoreListener);
    }

    @Override
    public void setAdapter(Adapter adapter) {
        if (!( adapter instanceof BaseRecycleAdapter)){
            return;
        }
        myLoadMoreAdapter = (BaseRecycleAdapter) adapter;
        super.setAdapter(myLoadMoreAdapter);

    }
    //自定義的接口方便回調(diào)
    public void setOnLoadListener(OnloadListener listener) {
        mOnLoadListener = listener;
    }

    //重寫OnScrollListener
    class LoadMoreDataListener extends OnScrollListener{
        private OnScrollListener listener;
        private int lastVisibleItem;


        public LoadMoreDataListener(OnScrollListener listener) {
            this.listener = listener;
        }

        /**
         * 當(dāng)目前顯示是最后一個(gè)條目的時(shí)候
         * @param recyclerView
         * @param newState
         */
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            //當(dāng)目前顯示是最后一個(gè)條目的時(shí)候繼續(xù)向下執(zhí)行
            if (newState == RecyclerView.SCROLL_STATE_IDLE &&lastVisibleItem + 1 == getAdapter().getItemCount()){
                if (mOnLoadListener != null && haveData) {
                    //改變底部foot狀態(tài)
                    myLoadMoreAdapter.changeMoreStatus(BaseRecycleAdapter.LOADING_MORE);
                    //通過(guò)接口回調(diào)回去
                    mOnLoadListener.OnLoadData();
                }
            }
            if (listener != null) {
                listener.onScrollStateChanged(recyclerView, newState);
            }
        }

        /**
         * 計(jì)算最后一個(gè)可見(jiàn)條目(lastVisibleItem)
         * 目前只支持 LinearLayoutManager和GridLayoutManager兩種類型
         * @param recyclerView
         * @param dx
         * @param dy
         */
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            if (getLayoutManager() instanceof LinearLayoutManager) {
                LinearLayoutManager lm = (LinearLayoutManager) getLayoutManager();
                lastVisibleItem = lm.findLastVisibleItemPosition();
            } else if (getLayoutManager() instanceof GridLayoutManager) {
                GridLayoutManager gm = (GridLayoutManager) getLayoutManager();
                 lastVisibleItem = gm.findLastVisibleItemPosition();
            }
            if (listener != null) {
                listener.onScrolled(recyclerView, dx, dy);
            }

        }

    }

    /**
     * 數(shù)據(jù)加載完成后調(diào)用
     * @param haveData
     */
    public void loadComplete(final boolean haveData) {
        //判斷時(shí)候還有數(shù)據(jù)
        this.haveData = haveData;

        //改變底部foot狀態(tài)
        if (!haveData) {
            myLoadMoreAdapter.changeMoreStatus(BaseRecycleAdapter.NO_MORE_DATA);
        } else {
            myLoadMoreAdapter.changeMoreStatus(BaseRecycleAdapter.PULL_UP_LOAD_MORE);
        }

    }

}


在布局文件使用

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.wckj.myrecyclerview.MainActivity">

    <com.wckj.myrecyclerview.MyRecyclerView
        android:id="@+id/my_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </com.wckj.myrecyclerview.MyRecyclerView>

</LinearLayout>

需要用到的接口

 interface OnloadListener {

    void OnLoadData();
}

通過(guò)自定義的adapter繼承上面的BaseRecycleAdapter

package com.wckj.myrecyclerview.Test;

import android.content.Context;
import android.widget.TextView;

import com.wckj.myrecyclerview.R;

import java.util.List;

/**
 * Created by HQL
 * on 2018/5/22 0022.
 */

public class MyRecyViewAdapter extends BaseRecycleAdapter<String> {
    public MyRecyViewAdapter(Context context) {
        super(context);
    }

    @Override
    public int getLayoutId(int type) {
        return R.layout.normal_item;
    }

    @Override
    public void onBindData(BaseHolder holder, int position, List<String> data) {

        TextView view = (TextView) holder.getView(R.id.tv_normal_item);
        view.setText(data.get(position));
    }

}

在Activity中使用

package com.wckj.myrecyclerview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.view.View;

import com.wckj.myrecyclerview.Test.MyRecyViewAdapter;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity implements OnItemClickListener {


    private MyRecyclerView myRecyclerView;
    private ArrayList<String> data = new ArrayList<>();
    private int j = 1;

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

        initData();
        myRecyclerView = (MyRecyclerView) findViewById(R.id.my_recyclerview);
        myRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
        MyRecyViewAdapter adapter = new MyRecyViewAdapter(this);
        adapter.setData(data);
        adapter.setOnItemClickListener(this);
        myRecyclerView.setAdapter(adapter);
        myRecyclerView.setOnLoadListener(new OnloadListener() {
            @Override
            public void OnLoadData() {
                if (j==5) {
                    //數(shù)據(jù)加載完成調(diào)用loadComplete菇怀,改變foot狀態(tài)
                    myRecyclerView.loadComplete(false);
                    return;
                }
                initData();
            }
        });
    }

    private void initData() {
        j++;

        for (int i=0;i<20;i++){
            data.add("我是一個(gè)粉刷匠凭舶,代號(hào)"+i);
        }
    }

    @Override
    public void onItemClick(int position, View view) {
        
    }
}

基本上就是這些,稍后代碼會(huì)上傳github有需要可以自行下載

代碼地址:https://github.com/aaahql2016/LoadMoreRecyclerview

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末爱沟,一起剝皮案震驚了整個(gè)濱河市帅霜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呼伸,老刑警劉巖身冀,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钝尸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡搂根,警方通過(guò)查閱死者的電腦和手機(jī)珍促,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)剩愧,“玉大人猪叙,你說(shuō)我怎么就攤上這事∪示恚” “怎么了穴翩?”我有些...
    開(kāi)封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)锦积。 經(jīng)常有香客問(wèn)我芒帕,道長(zhǎng),這世上最難降的妖魔是什么充包? 我笑而不...
    開(kāi)封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任副签,我火速辦了婚禮,結(jié)果婚禮上基矮,老公的妹妹穿的比我還像新娘淆储。我一直安慰自己,他們只是感情好家浇,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布本砰。 她就那樣靜靜地躺著,像睡著了一般钢悲。 火紅的嫁衣襯著肌膚如雪点额。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天莺琳,我揣著相機(jī)與錄音还棱,去河邊找鬼。 笑死惭等,一個(gè)胖子當(dāng)著我的面吹牛珍手,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辞做,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼琳要,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了秤茅?” 一聲冷哼從身側(cè)響起稚补,我...
    開(kāi)封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎框喳,沒(méi)想到半個(gè)月后课幕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體厦坛,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年撰豺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了粪般。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡污桦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出匙监,到底是詐尸還是另有隱情凡橱,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布亭姥,位于F島的核電站稼钩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏达罗。R本人自食惡果不足惜坝撑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望粮揉。 院中可真熱鬧巡李,春花似錦、人聲如沸扶认。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辐宾。三九已至狱从,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叠纹,已是汗流浹背季研。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留誉察,地道東北人与涡。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像冒窍,于是被迫代替她去往敵國(guó)和親递沪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345