RecyclerView上拉刷新,下拉加载更多

RecyclerView上拉刷新,下拉加载更多

经常在写项目的时候都会碰到RecyclerView上拉刷新,下拉加载更多的功能,今天自己来捋一捋。

效果图

这里写图片描述

下拉刷新(SwipeRefreshLayout)

这是Google自己出的下拉刷新控件,其实还挺好看的,这里我们只要知道其中几个方法就可以了。
1. setColorSchemeResources
2. setOnRefreshListener
第一个是设置刷新时小圆圈的颜色,可以设置4中颜色切换。
第二个方法是设置刷新监听。这个接口里面有个onRefresh方法,刷新任务就在这里面执行。
所以总而言之下拉刷新才用官方的还是so easy.
在刷新任务完成后,你就可以把新数注入到adapter里面,刷新下就可以完成下拉刷新。

上拉加载更多

首先需要判断是否滑动到底部了,所以写个抽象类,继承RecyclerView的OnScrollListener

public abstract class RecyclerOnScrollListener extends RecyclerView.OnScrollListener {
    private int mPreviousTotal = 0;
    private boolean mLoading = true;
    int mFirstVisibleItem, mVisibleItemCount, mTotalItemCount;//第一个item,显示的item总数,整个item总数

    private int currentPage = 1;

    private LinearLayoutManager mLinearLayoutManager;

    public RecyclerOnScrollListener(
            LinearLayoutManager linearLayoutManager) {
        this.mLinearLayoutManager = linearLayoutManager;
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        mVisibleItemCount = recyclerView.getChildCount();
        mTotalItemCount = mLinearLayoutManager.getItemCount();
        mFirstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();

        if (mLoading) {
            if (mTotalItemCount > mPreviousTotal) {
                mLoading = false;
                mPreviousTotal = mTotalItemCount;
            }
        }
        if (!mLoading
                && (mTotalItemCount - mVisibleItemCount) <= mFirstVisibleItem) {
            currentPage++;
            onLoadMore(currentPage);
            mLoading = true;
        }
    }

    public abstract void onLoadMore(int currentPage);
}

这个类主要是判断是否滚动到了底部,滚动到了底部就去执行加载更多方法

添加底部加载更多布局

因为加载更多是属于耗时操作,为了提高用户体验,所以很有必要加个进度条提示。
进度条可以当做为一个item,在滑动到最后的时候就让他显示出来。
这里我采用了牛人的一个类,来辅助我们实现这个效果。站在巨人的肩膀上就可以看得更远。
到时直接把自己的适配器传递进去就行了。先贴上大神的代码

public class HeaderViewRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private static final int HEADERS_START = Integer.MIN_VALUE;
    private static final int FOOTERS_START = Integer.MIN_VALUE + 10;
    private static final int ITEMS_START = Integer.MIN_VALUE + 20;
    private static final int ADAPTER_MAX_TYPES = 100;

    private RecyclerView.Adapter mWrappedAdapter;
    private List<View> mHeaderViews, mFooterViews;
    private Map<Class, Integer> mItemTypesOffset;

    /**
     * Construct a new header view recycler adapter
     * @param adapter The underlying adapter to wrap
     */
    public HeaderViewRecyclerAdapter(RecyclerView.Adapter adapter) {
        mHeaderViews = new ArrayList<View>();
        mFooterViews = new ArrayList<View>();
        mItemTypesOffset = new HashMap<Class, Integer>();
        setWrappedAdapter(adapter);
    }

    /**
     * Replaces the underlying adapter, notifying RecyclerView of changes
     * @param adapter The new adapter to wrap
     */
    public void setAdapter(RecyclerView.Adapter adapter) {
        if(mWrappedAdapter != null && mWrappedAdapter.getItemCount() > 0) {
            notifyItemRangeRemoved(getHeaderCount(), mWrappedAdapter.getItemCount());
        }
        setWrappedAdapter(adapter);
        notifyItemRangeInserted(getHeaderCount(), mWrappedAdapter.getItemCount());
    }

    @Override
    public int getItemViewType(int position) {
        int hCount = getHeaderCount();
        if (position < hCount) return HEADERS_START + position;
        else {
            int itemCount = mWrappedAdapter.getItemCount();
            if (position < hCount + itemCount) {
                return getAdapterTypeOffset() + mWrappedAdapter.getItemViewType(position - hCount);
            }
            else return FOOTERS_START  + position - hCount - itemCount;
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        if (viewType < HEADERS_START + getHeaderCount())
            return new StaticViewHolder(mHeaderViews.get(viewType - HEADERS_START));
        else if (viewType < FOOTERS_START + getFooterCount())
            return new StaticViewHolder(mFooterViews.get(viewType - FOOTERS_START));
        else {
            return mWrappedAdapter.onCreateViewHolder(viewGroup, viewType - getAdapterTypeOffset());
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        int hCount = getHeaderCount();
        if (position >= hCount && position < hCount + mWrappedAdapter.getItemCount())
            mWrappedAdapter.onBindViewHolder(viewHolder, position - hCount);
    }

    /**
     * Add a static view to appear at the start of the RecyclerView. Headers are displayed in the
     * order they were added.
     * @param view The header view to add
     */
    public void addHeaderView(View view) {
        mHeaderViews.add(view);
    }

    /**
     * Add a static view to appear at the end of the RecyclerView. Footers are displayed in the
     * order they were added.
     * @param view The footer view to add
     */
    public void addFooterView(View view) {
        mFooterViews.add(view);
    }

    @Override
    public int getItemCount() {
        return getHeaderCount() + getFooterCount() + getWrappedItemCount();
    }

    /**
     * @return The item count in the underlying adapter
     */
    public int getWrappedItemCount() {
        return mWrappedAdapter.getItemCount();
    }

    /**
     * @return The number of header views added
     */
    public int getHeaderCount() {
        return mHeaderViews.size();
    }

    /**
     * @return The number of footer views added
     */
    public int getFooterCount() {
        return mFooterViews.size();
    }

    private void setWrappedAdapter(RecyclerView.Adapter adapter) {
        if (mWrappedAdapter != null) mWrappedAdapter.unregisterAdapterDataObserver(mDataObserver);
        mWrappedAdapter = adapter;
        Class adapterClass = mWrappedAdapter.getClass();
        if(!mItemTypesOffset.containsKey(adapterClass)) putAdapterTypeOffset(adapterClass);
        mWrappedAdapter.registerAdapterDataObserver(mDataObserver);
    }

    private void putAdapterTypeOffset(Class adapterClass) {
        mItemTypesOffset.put(adapterClass, ITEMS_START + mItemTypesOffset.size() * ADAPTER_MAX_TYPES);
    }

    private int getAdapterTypeOffset() {
        return mItemTypesOffset.get(mWrappedAdapter.getClass());
    }

    private RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() {
        @Override
        public void onChanged() {
            super.onChanged();
            notifyDataSetChanged();
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
            super.onItemRangeChanged(positionStart, itemCount);
            notifyItemRangeChanged(positionStart + getHeaderCount(), itemCount);
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            super.onItemRangeInserted(positionStart, itemCount);
            notifyItemRangeInserted(positionStart + getHeaderCount(), itemCount);
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            super.onItemRangeRemoved(positionStart, itemCount);
            notifyItemRangeRemoved(positionStart + getHeaderCount(), itemCount);
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            super.onItemRangeMoved(fromPosition, toPosition, itemCount);
            int hCount = getHeaderCount();
            // TODO: No notifyItemRangeMoved method?
            notifyItemRangeChanged(fromPosition + hCount, toPosition + hCount + itemCount);
        }
    };

    private static class StaticViewHolder extends RecyclerView.ViewHolder {

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

这个类很好用,可以随意添加头和尾。它的主要原理也就是先获取源数据的item数,然后根据你添加的布局类型(头或者尾)去动态的添加到recyclerview里面。
最后贴上activity源代码吧,看看如何使用

public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
    private SwipeRefreshLayout mRefreshLayout;
    private RecyclerView mRecyclerView;
    private MyAdapter mAdapter;
    private List<String> mLists;
    private HeaderViewRecyclerAdapter mHeaderAdapter;
    private List<String> list=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRefreshLayout= (SwipeRefreshLayout) findViewById(R.id.refreshlayout);
        mRecyclerView= (RecyclerView) findViewById(R.id.recyclerview);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(linearLayoutManager);

        mRefreshLayout.setColorSchemeResources(
                R.color.colorAccent,
                R.color.colorPrimary,
                R.color.read,
                R.color.blue
        );
        mRefreshLayout.setOnRefreshListener(this);
        initdata();
        mAdapter=new MyAdapter(MainActivity.this,mLists);
        mHeaderAdapter=new HeaderViewRecyclerAdapter(mAdapter);
        mRecyclerView.setAdapter(mHeaderAdapter);
        initFootView();
        mRecyclerView.addOnScrollListener(new RecyclerOnScrollListener(linearLayoutManager) {
            @Override
            public void onLoadMore(int currentPage) {
                loadMoreData();
            }
        });
    }

    private void initFootView() {
        View loadMoreView = LayoutInflater
                .from(MainActivity.this)
                .inflate(R.layout.item_foot_layout, mRecyclerView, false);
        mHeaderAdapter.addFooterView(loadMoreView);
    }

    private void initdata() {
        mLists=new ArrayList<>();
        for (int i=0;i<15;i++){
            mLists.add(""+i+" itme");
        }
    }

    /**
     * 测试数据,延迟两秒执行
     */
    private void loadMoreData(){
        Handler handler=new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                loadData();
            }
        },2000);

    }

    private void loadData(){
        list.clear();
        for (int i=0;i<5;i++){
            list.add("上拉加载出来的数据");
        }
        mLists.addAll(list);
        mHeaderAdapter.notifyDataSetChanged();
    }

    @Override
    public void onRefresh() {
        Handler handler=new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mRefreshLayout.setRefreshing(false);
                Toast.makeText(MainActivity.this,"数据刷新了",Toast.LENGTH_SHORT).show();
            }
        },2000);
    }
}

这里数据都是测试数据,实际上可以根据自己需求去获取的,获取完后添加到原数据里面,然后刷新一下就OK了(这里先不用考虑局部刷新……)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值