Android之RecycleView下拉刷新上滑加载更多

本文注意记录一些零碎的东西

闲来无事,自定义了一个下拉刷新上滑加载更多的RecycleView,虽说网络上比我写得好的太多了,小小纪录一下

《Android之RecycleView下拉刷新上滑加载更多》

RefreshRecycleView.java

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.ColorRes;
import android.support.annotation.IdRes;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import java.util.List;

/**
 * 上拉刷新 下滑加载更多
 * 暂时只支持 LinearLayoutManager
 * 原理:
 *      下滑 使用 SwipeRefreshLayout
 *      上拉 使用 屏幕上面的顶部item和顶部item相关,获取到RecyclerView列表中Item View的个数
 *      ---findFirstVisibleItemPosition(),findFirstCompletlyVisibleItemPosition()
 *      ---findLastVisibleItemPosition(),findLastCompletlyVisibleItemPosition()
 *      ---getItemCount()
 * Created by slack
 * on 17/3/8 下午1:58.
 * how to use :
 * 1.mRefreshRecycleView = (RefreshRecycleView) findViewById(R.id.xxx);
 * 2.mRefreshRecycleView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
 * 3.mRefreshRecycleView.setAdapter(mContactsAdapter);
 */

public class RefreshRecycleView extends FrameLayout {

    private SwipeRefreshLayout mSwipeRefreshLayout;
    private RecyclerView mRecyclerView;
    private LinearLayoutManager mLinearLayoutManager;
    private RecyclerView.Adapter mAdapter;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    private RefreshListener mRefreshListener;
    private int mLastVisibleItemPosition;// 最后一个可见 item position

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

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

    public RefreshRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    /**
     * important  !!!
     * RecyclerView.setLayoutManager
     * @param manager manager
     * @return
     */
    public RefreshRecycleView setLayoutManager(LinearLayoutManager manager){
        mLinearLayoutManager = manager;
        mRecyclerView.setLayoutManager(manager);
        return this;
    }

    /**
     * important  !!!
     * RecyclerView.setAdapter
     * @param adapter adapter
     * @return
     */
    public RefreshRecycleView setAdapter(RecyclerView.Adapter adapter){
        mAdapter = adapter;
        mRecyclerView.setAdapter(adapter);
        return this;
    }

    /**
     * 异步需要手动 关闭 下拉 刷新
     */
    public void finishRefresh() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mAdapter.notifyDataSetChanged();
                mSwipeRefreshLayout.setRefreshing(false);
                //
            }
        });
    }

    /**
     * 设置进度条的颜色主题,最多设置四种
     * @param colorResIds ids
     * @return
     */
    public RefreshRecycleView setRefreshColorResources(@ColorRes int... colorResIds){
        mSwipeRefreshLayout.setColorSchemeResources(colorResIds);
        return this;
    }

    /**
     * 设置滑动 刷新 监听
     * @param l RefreshListener
     * @return
     */
    public RefreshRecycleView setRefreshListener(RefreshListener l){
        mRefreshListener = l;
        return this;
    }

    public RecyclerView getRecyclerView(){
        return mRecyclerView;
    }

    private void initView(Context context) {
        mSwipeRefreshLayout = new SwipeRefreshLayout(context);
        mRecyclerView = new RecyclerView(context);
        mSwipeRefreshLayout.addView(mRecyclerView);
        addView(mSwipeRefreshLayout);
        initRefreshLayout();
        initRecyclerView();
    }

    private void initRecyclerView() {
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.addOnScrollListener(mOnScrollListener);
    }

    private void initRefreshLayout() {
        /**
         * 设置刷新时动画的颜色,可以设置4个
         */
        mSwipeRefreshLayout.setColorSchemeResources(
                android.R.color.holo_blue_light,
                android.R.color.holo_red_light,
                android.R.color.holo_orange_light,
                android.R.color.holo_green_light);
        /**
         * 设置下拉监听,当用户下拉的时候会去执行回调
         */
        mSwipeRefreshLayout.setOnRefreshListener(mOnRefreshListener);
        /**
         * 这句话是为了,第一次进入页面的时候显示加载进度条
         * 调整进度条距离屏幕顶部的距离 (boolean scale, int start, int end)
         */
        mSwipeRefreshLayout.setProgressViewOffset(
                false,
                0,
                (int) TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_DIP,24,getResources().getDisplayMetrics()));
        /**
         * setRefreshing(boolean refreshing) 设置SwipeRefreshLayout当前是否处于刷新状态,
         * 一般是在请求数据的时候设置为true,在数据被加载到View中后,设置为false。
         */
    }

    private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener =
        new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                if(mRefreshListener != null) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            if(mRefreshListener.onPullToRefresh()) {
                                finishRefresh();
                            }
                        }
                    }).start();
                }else {
                    finishRefresh();
                }
            }
        };

    private RecyclerView.OnScrollListener mOnScrollListener =
            new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == RecyclerView.SCROLL_STATE_IDLE &&
                    mLastVisibleItemPosition + 1 == mAdapter.getItemCount()) {
                if(mRefreshListener != null){
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            if(mRefreshListener.onUpGlideLoadMore()) {
                                finishRefresh();
                            }
                        }
                    }).start();
                }else {
                    finishRefresh();
                }
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            mLastVisibleItemPosition = mLinearLayoutManager.findLastVisibleItemPosition();
        }
    };

    /**
     * 如果需要 上滑加载更多 的 布局 adapter need
     *      extends this
     *      extends ItemViewHolder
     * 原理 onCreateViewHolder(ViewGroup paren,int viewType) 第二个参数viewType,支持多套布局显示
     */
    public static abstract class RefreshFootAdapter<T extends RefreshFootAdapter.BaseViewHolder>
            extends RecyclerView.Adapter <T>{

        private final int TYPE_ITEM =0;  //普通 Item View
        private final int TYPE_FOOTER = 1;  //底部 Foot View
        private final String FootViewTag = "FootView";
        private List<?> mDatas ;
        protected LayoutInflater mLayoutInflater;
        private Context mContext;

        public RefreshFootAdapter(Context context, List<?> mDatas) {
            mContext = context;
            this.mDatas = mDatas;
            mLayoutInflater = LayoutInflater.from(context);
        }

        /**
         * 进行判断显示类型,来创建返回不同的View
         */
        @Override
        public T onCreateViewHolder(ViewGroup parent, int viewType) {
            if(viewType==TYPE_ITEM){
                return onItemView (parent, viewType);
            }else if(viewType==TYPE_FOOTER){
                return onFootView(parent, viewType);
            }
            return null;
        }

        /**
         * return new ItemViewHolder(xxx)
         */
        protected abstract T onItemView(ViewGroup parent, int viewType);

        /**
         * foot view
         */
        protected abstract T onFootView(ViewGroup parent, int viewType);

        /**
         * 返回的Item数量在数据的基础上面+1,增加一项FootView布局项
         */
        @Override
        public int getItemCount() {
            return mDatas == null ? 1 : mDatas.size() + 1;
        }

        /**
         * 最后一个item设置为footerView
         * position  0,1,2,3...
         */
        @Override
        public int getItemViewType(int position) {
            if (position + 1 == getItemCount()) {
                return TYPE_FOOTER;
            } else {
                return TYPE_ITEM;
            }
        }

        @Override
        public void onBindViewHolder(T holder, int position) {
            holder.bindView(holder,position);
        }

        public abstract class BaseViewHolder extends RecyclerView.ViewHolder{

            private View mView;

            public BaseViewHolder(View itemView) {
                super(itemView);
                mView = itemView;
            }

            protected abstract void bindView(RecyclerView.ViewHolder holder,int pos);

            protected View findViewById(@IdRes int id){
                return mView.findViewById(id);
            }

        }

    }


    /**
     * 方法都是在子线程里运行的
     * return 是否 同步执行代码(true 同步获取数据,false 异步获取数据)
     * 异步需要手动 关闭 下拉 刷新
     */
    public interface RefreshListener{
        boolean onPullToRefresh();
        boolean onUpGlideLoadMore();
    }
}


使用比较简单,直接把这个自定义文件拷贝了就好,需要注意的是 回调方法都是在 子线程里运行的,毕竟加载数据要么联网要么读取文件,不需要在主线程里执行,返回值的意思是判断是否在子线程里同步获取数据,

如果异步获取 返回 false,数据获取到后需要主动调用 

mRefreshRecycleView.finishRefresh();  刷新数据

如何使用:

final List<String> data = new ArrayList<String>(){
            {
                for (int i= 0;i<20;i++){
                    add("item " + i);
                }
            }
        };
        
        mRefreshRecycleView.setLayoutManager(
                new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
        
        mRefreshRecycleView.setAdapter(new ReshAdapter(mRefreshRecycleView.getContext(),data));
        mRefreshRecycleView.setRefreshListener(new RefreshRecycleView.RefreshListener() {
            @Override
            public boolean onPullToRefresh() {
                data.clear();
                for (int i= 0;i<20;i++){
                    data.add("onPullToRefresh " + i);
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return true;
            }

            @Override
            public boolean onUpGlideLoadMore() {
                for (int i= 0;i<5;i++){
                    data.add("onUpGlideLoadMore " + i);
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return true;
            }
        });

里面封装了一个adapter ,主要是处理上滑时没有界面,如果不需要上滑加载更多的提示界面,直接无视下面的内容

自定义adapter extends RefreshRecycleView.RefreshFootAdapter  提供Item 布局 和 foot 提示正在加载数据的布局

class ReshAdapter extends RefreshRecycleView.RefreshFootAdapter {

        private List<String> mDatas;

        ReshAdapter(Context context, List<String> datas) {
            super(context, datas);
            this.mDatas = datas;
        }

        @Override
        protected ReshViewHolder onItemView(ViewGroup parent, int viewType) {
            return new ReshViewHolder(
                    mLayoutInflater.inflate(R.layout.item_contact,parent,false));
        }

        @Override
        protected FootViewHolder onFootView(ViewGroup parent, int viewType) {
            return new FootViewHolder(
                    mLayoutInflater.inflate(R.layout.item_contact,parent,false));
        }

        class ReshViewHolder extends BaseViewHolder{

            private TextView textView;

            public ReshViewHolder(View itemView) {
                super(itemView);
                textView = (TextView)findViewById(R.id.contact_name);
            }

            @Override
            protected void bindView(RecyclerView.ViewHolder holder, int pos) {

                textView.setText(mDatas.get(pos));
            }


        }

        class FootViewHolder extends BaseViewHolder{

            private TextView textView;

            public FootViewHolder(View itemView) {
                super(itemView);
                textView = (TextView)findViewById(R.id.contact_name);
            }

            @Override
            protected void bindView(RecyclerView.ViewHolder holder, int pos) {

                textView.setText("loading more ...");
            }


        }
    }

    原文作者:CL_slacking
    原文地址: https://blog.csdn.net/I_do_can/article/details/60875159
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞