RecyclerView+SwipeRefreshLayout實(shí)現(xiàn)下拉刷新與上拉加載

LRecyclerViewActivity.java

/**
 * <p> </p>
 * Created by 行走的老者 on 2017/11/13 0013.
 */
public class LRecyclerViewActivity extends AppCompatActivity {
    private LRecyclerView mLRecyclerView;
    private TestAdapter mTestAdapter;
    private SwipeRefreshLayout mRefreshLayout;

    private List<String> mDataList;

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

        mLRecyclerView = findViewById(R.id.recycler_view);
        mRefreshLayout = findViewById(R.id.switch_refresh);

        mLRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mTestAdapter = new TestAdapter();
        mLRecyclerView.setAdapter(mTestAdapter);

        mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                if (mLRecyclerView.isLoading()) {
                    mRefreshLayout.setRefreshing(false);
                    return;
                }

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mRefreshLayout.setRefreshing(false);
                                mDataList.add(0, "刷新.出來的數(shù)據(jù).....");
                                mTestAdapter.setDataList(mDataList);
                            }
                        });
                    }
                }).start();
            }
        });


        mDataList = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            mDataList.add("第一頁加載......" + i);
        }
        mTestAdapter.setDataList(mDataList);

        mLRecyclerView.setOnLoadingListener(new LRecyclerView.OnLoadingListener() {
            @Override
            public void onLoading() {
                if (mRefreshLayout.isRefreshing()) return;

                mTestAdapter.setStatus(LoadingAdapter.STATUS_LOADING);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mLRecyclerView.finishLoading();
                                mTestAdapter.setStatus(LoadingAdapter.STATUS_LOADED);

                                Log.i("liao", "......................mPage=" + mPage);
                                if (mPage > 4) {
                                    Toast.makeText(LRecyclerViewActivity.this, "沒有更多數(shù)據(jù)了", Toast.LENGTH_SHORT).show();
                                    return;
                                }
                                mPage++;

                                for (int i = 0; i < 50; i++) {
                                    mDataList.add("上拉加載.出來的數(shù)據(jù)....." + i);
                                }
                                mTestAdapter.setDataList(mDataList);
                            }
                        });
                    }
                }).start();
            }
        });
    }

    private int mPage = 1;


    public class TestAdapter extends LoadingAdapter<String> {

        @Override
        public RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType) {
            return new ItemViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false));
        }

        @Override
        protected void onBindHolder(RecyclerView.ViewHolder holder, int position) {
            if (holder instanceof ItemViewHolder) {
                ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
                itemViewHolder.mTextView.setText(mDataList.get(position));
            }
        }

        public class ItemViewHolder extends RecyclerView.ViewHolder {
            TextView mTextView;

            public ItemViewHolder(View itemView) {
                super(itemView);
                mTextView = itemView.findViewById(R.id.text);
            }
        }
    }
}

xml資源

activity_lrecycler_view.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/switch_refresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <cn.jhworks.demo.loading.LRecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical"/>
</android.support.v4.widget.SwipeRefreshLayout>

item_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="60dp">

    <TextView
        android:id="@+id/text"
        android:gravity="center"
        android:text="helll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

下面是上拉加載實(shí)現(xiàn)

實(shí)現(xiàn)見代碼:

LRecyclerView .java

/**
 * <p> </p>
 * Created by 行走的老者 on 2017/11/13 0013.
 */
public class LRecyclerView extends RecyclerView {

    private boolean mIsLoading = false;
    private int initPreItem = 3;

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

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

    public LRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        addOnScrollListener(mOnScrollListener);
    }

    public void finishLoading() {
        mIsLoading = false;
    }

    public boolean isLoading() {
        return mIsLoading;
    }

    private OnScrollListener mOnScrollListener = new OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
           /* Log.i("liao", "newState=" + newState);

            //第一種方式  有個(gè)bug:當(dāng)最后一個(gè)item剛顯示出來的時(shí)候停止滑動(dòng)這個(gè)時(shí)候也會(huì)觸發(fā)滑動(dòng)到底部的操作
            LayoutManager layoutManager = getLayoutManager();
            int itemCount = layoutManager.getItemCount();
            int lastVisibleItemPosition = 0;
            if (layoutManager instanceof LinearLayoutManager) {
                LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
                lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
            } else if (layoutManager instanceof StaggeredGridLayoutManager) {
                StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
                //得到這個(gè)數(shù)組后再取到數(shù)組中position值最大的那個(gè)就是最后顯示的position值了
                int[] lastPositions = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
                staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
                lastVisibleItemPosition = findMax(lastPositions);
            }

            if (!mIsLoading && ((lastVisibleItemPosition + 1) >= itemCount) && newState == SCROLL_STATE_IDLE) {

                Log.i("liao", "加載.....lastVisibleItemPosition=" + lastVisibleItemPosition + ",itemCount=" + itemCount);
                mIsLoading = true;
                post(new Runnable() {
                    @Override
                    public void run() {
                        if (mOnLoadingListener != null) {
                            mOnLoadingListener.onLoading();
                        }
                    }
                });
            }*/

            //第二種方式
            //得到當(dāng)前顯示的最后一個(gè)item的view
            View lastChildView = recyclerView.getLayoutManager().getChildAt(recyclerView.getLayoutManager().getChildCount() - 1);
            //得到lastChildView的bottom坐標(biāo)值
            int lastChildBottom = lastChildView.getBottom();
            //得到Recycler view的底部坐標(biāo)減去底部padding值魁袜,也就是顯示內(nèi)容最底部的坐標(biāo)
            int recyclerBottom = recyclerView.getBottom() - recyclerView.getPaddingBottom();
            //通過這個(gè)lastChildView得到這個(gè)view當(dāng)前的position值
            int lastPosition = recyclerView.getLayoutManager().getPosition(lastChildView);

            //判斷l(xiāng)astChildView的bottom值跟recyclerBottom
            //判斷l(xiāng)astPosition是不是最后一個(gè)position
            //如果兩個(gè)條件都滿足則說明是真正的滑動(dòng)到了底部
            if (!mIsLoading && lastChildBottom == recyclerBottom && lastPosition == recyclerView.getLayoutManager().getItemCount() - 1
                    && newState == SCROLL_STATE_IDLE) {
                mIsLoading = true;
                post(new Runnable() {
                    @Override
                    public void run() {
                        if (mOnLoadingListener != null) {
                            mOnLoadingListener.onLoading();
                        }
                    }
                });
            }
        }
    };

    //找到數(shù)組中的最大值
    private int findMax(int[] lastPositions) {
        int max = lastPositions[0];
        for (int value : lastPositions) {
            if (value > max) {
                max = value;
            }
        }
        return max;
    }

    private OnLoadingListener mOnLoadingListener;

    public void setOnLoadingListener(OnLoadingListener onLoadingListener) {
        mOnLoadingListener = onLoadingListener;
    }

    public interface OnLoadingListener {
        void onLoading();
    }
}

LoadingAdapter.java ----具有加載更多布局的adapter


/**
 * <p> </p>
 * Created by 行走的老者 on 2017/11/13 0013.
 */
public abstract class LoadingAdapter<B> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final int FOOTER = 10000;
    private static final int NORMAL = 10001;

    public static final int STATUS_LOADING = 10;
    public static final int STATUS_LOADED = 11;
//    public static final int STATUS_LOADED = 11;

    @IntDef({STATUS_LOADING, STATUS_LOADED})
    public @interface Status {
    }

    private int mStatus = STATUS_LOADED;

    private List<B> mDataList;


    public void setDataList(List<B> dataList) {
        mDataList = dataList;
        notifyDataSetChanged();
    }

    public void setStatus(@Status int status) {
        mStatus = status;
        notifyDataSetChanged();
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == FOOTER) {
            return new LoadingViewHolder(LayoutInflater.from(
                    parent.getContext()).inflate(R.layout.loading_more_layout, parent, false));
        } else
            return onCreateHolder(parent, viewType);
    }

    protected abstract RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType);

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof LoadingViewHolder) return;
        onBindHolder(holder, position);
    }

    protected abstract void onBindHolder(RecyclerView.ViewHolder holder, int position);

    @Override
    public int getItemViewType(int position) {
        if (position == getItemCount() - 1 && mStatus == STATUS_LOADING) {
            return FOOTER;
        }
        return NORMAL;
    }

    @Override
    public int getItemCount() {
        return mDataList == null ? 0 : mDataList.size() + (mStatus == STATUS_LOADING ? 1 : 0);
    }

    //解決GridLayoutManager 占用問題
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if (manager instanceof GridLayoutManager) {
            final GridLayoutManager gridManager = ((GridLayoutManager) manager);
            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    return isFooter(position) ? gridManager.getSpanCount() : 1;
                }
            });
        }
    }

    private boolean isFooter(int position) {
        return mStatus == STATUS_LOADING && position == getItemCount();
    }

    //處理StaggeredGridLayoutManager 占用問題
    @Override
    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
        super.onViewAttachedToWindow(holder);
        if (isStaggeredGridLayout(holder)) {
            handleLayoutIfStaggeredGridLayout(holder, holder.getLayoutPosition());
        }
    }

    private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) {
        ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
        return layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams;
    }

    private void handleLayoutIfStaggeredGridLayout(RecyclerView.ViewHolder holder, int position) {
        if (/*isHeader(position) ||*/ isFooter(position)) {
            StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
            p.setFullSpan(true);
        }
    }

    public static class LoadingViewHolder extends RecyclerView.ViewHolder {

        public LoadingViewHolder(View itemView) {
            super(itemView);
        }
    }

    public static class NormalViewHolder extends RecyclerView.ViewHolder {

        public NormalViewHolder(View itemView) {
            super(itemView);
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末箕速,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子之碗,更是在濱河造成了極大的恐慌,老刑警劉巖誊薄,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玲献,死亡現(xiàn)場離奇詭異,居然都是意外死亡欢搜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門谴轮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炒瘟,“玉大人,你說我怎么就攤上這事第步〈埃” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵粘都,是天一觀的道長廓推。 經(jīng)常有香客問我,道長驯杜,這世上最難降的妖魔是什么受啥? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任做个,我火速辦了婚禮鸽心,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘居暖。我一直安慰自己顽频,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布太闺。 她就那樣靜靜地躺著糯景,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蟀淮,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天最住,我揣著相機(jī)與錄音,去河邊找鬼怠惶。 笑死涨缚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的策治。 我是一名探鬼主播脓魏,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼通惫!你這毒婦竟也來了茂翔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤履腋,失蹤者是張志新(化名)和其女友劉穎珊燎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體遵湖,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡俐末,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奄侠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卓箫。...
    茶點(diǎn)故事閱讀 40,505評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖垄潮,靈堂內(nèi)的尸體忽然破棺而出烹卒,到底是詐尸還是另有隱情,我是刑警寧澤弯洗,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布旅急,位于F島的核電站,受9級特大地震影響牡整,放射性物質(zhì)發(fā)生泄漏藐吮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一逃贝、第九天 我趴在偏房一處隱蔽的房頂上張望谣辞。 院中可真熱鬧,春花似錦沐扳、人聲如沸泥从。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽躯嫉。三九已至纱烘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間祈餐,已是汗流浹背擂啥。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帆阳,地道東北人啤它。 一個(gè)月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像舱痘,于是被迫代替她去往敵國和親变骡。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容