码迷,mamicode.com
首页 > 其他好文 > 详细

SwipeRefreshLayout+RecyclerView实现下拉刷新上拉自动加载

时间:2016-07-10 18:57:56      阅读:660      评论:0      收藏:0      [点我收藏+]

标签:

在实际开发中,为了节省开发周期,下拉刷新上拉加载通常都会采取使用一些第三方库,典型的就是用PullToRefresh,XListView等等,还有就是谷歌推荐的SwipeRefreshLayout,可惜没有上拉加载功能,需要自己去实现一个上拉加载的脚View,再加上现在代替ListView的RecyclerView+CardView使用的频率也是也来也高,不得不说,CardView效果确实很好看,一个一个的小卡片,用户体验好,I like it!!!废话不说了,奔主题!今天也玩了一下SwipeRefreshLayout+RecyclerView实现下拉刷新上拉自动加载。
我最初的想法就是:先利用RecyclerView添加不同的item布局,上面是一个轮播的ViewPager,下面是一个一个的列表数据,当滑到到底部的时候,可以自动加载更多,当然要在底部添加一个个性化的视图显示正在加载,即脚View。

先看一下RecyclerView如何加载不同的item的,通过getItemViewType实现,注意:继承的是RecyclerView.Adapter。
1.设置3个常量,分别是ViewPager部分,中间的列表数据部分,和底部的正在加载脚部分:

private static final int ITEM_HEADER = 0;
    private static final int ITEM_ITEM = 1;
    private static final int ITEM_LOAD_FOOTER = 2;

三个上拉加载更多的显示状态:

//上拉加载更多
    public static final int PULLUP_LOAD_MORE=0;
    //正在加载...
    public static final int ISLOADING=1;
    //上拉加载的显示状态,初始为0
    private int load_more_status=0;

Adapter里设置的一个方法,方便Activity调用改变加载状态来显示不同的加载信息(上拉加载更多,加载中…):

public void changeMoreStatus(int status){
        load_more_status=status;
        notifyDataSetChanged();
    }

2.创建Viewholder:

@Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if(viewType==ITEM_HEADER){
            View view = LayoutInflater.from(context).inflate(R.layout.item_header,parent,false);
            return new HeaderViewHolder(view);
        }else if(viewType==ITEM_ITEM){
            View view = LayoutInflater.from(context).inflate(R.layout.item_item,parent,false);
            return new ItemViewHolder(view);
        }else if(viewType==ITEM_LOAD_FOOTER){
            View view = LayoutInflater.from(context).inflate(R.layout.refresh_footer,parent,false);
            return new LoadFooterViewHolder(view);
        }
        return null;
    }

3.绑定数据:

@Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
       if(holder instanceof ItemViewHolder){
            ((ItemViewHolder) holder).mTextView.setText(mListData.get(position-1));
        }else if(holder instanceof LoadFooterViewHolder){
            LoadFooterViewHolder footer = (LoadFooterViewHolder) holder;
            switch(load_more_status){
                case PULLUP_LOAD_MORE:
                    footer.progressbar.setVisibility(View.GONE);
                    footer.loadmore_text.setText("上拉加载更多");
                    break;
                case ISLOADING:
                    footer.progressbar.setVisibility(View.VISIBLE);
                    footer.loadmore_text.setText("正在加载...");
                    break;
            }
        }
        //列表数据的点击事件监听,注意:这里的position是比正常的position+1的,因为多加了一个头部View
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context, "点击了位置"+position, Toast.LENGTH_SHORT).show();
            }
        });
    }

说明:这里只处理了中间列表的数据,ViewPager部分的数据不在这处理。

4.获取item的数量:

@Override
    public int getItemCount() {
        return mListData.size()+2;
    }

说明:+2是因为除了正常的列表数据外,还多加了一个头和脚View

5.ItemView类型:

@Override
    public int getItemViewType(int position) {
        if(position==0){
            return ITEM_HEADER;
        }else if(position==mListData.size()+1){
            return ITEM_LOAD_FOOTER;
        }else {
            return ITEM_ITEM;
        }
    }

说明:第一项添加一个ViewPager,最后一项添加一个正在加载的脚View,剩下的中间的全部就是正常的列表数据。

下面的三个view内部类:

class HeaderViewHolder extends RecyclerView.ViewHolder{
        private ViewPager mViewPager;
        private LinearLayout linearlayout;
        private ImageView[] points;
        private Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                mViewPager.setCurrentItem(mViewPager.getCurrentItem()+1);
                handler.sendEmptyMessageDelayed(1,3000);
            }
        };
        public HeaderViewHolder(View itemView) {
            super(itemView);
            mViewPager = (ViewPager) itemView.findViewById(R.id.viewpager);
            linearlayout = (LinearLayout) itemView.findViewById(R.id.linearlayout);
            //下面两句要在setAdapter之前调用,否则会出现先加载最后一张图片的情况
            mViewPager.setCurrentItem(Integer.MAX_VALUE/2);
            handler.sendEmptyMessageDelayed(1,3000);
            mViewPager.setAdapter(new MyViewPagerAdapter(context, imagesUrl));
            initPoint();
            mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

                }

                @Override
                public void onPageSelected(int position) {
                    for(int i=0;i<imagesUrl.length;i++){
                        if(position%imagesUrl.length==i){
                            points[i].setImageResource(R.drawable.point_focus);
                        }else {
                            points[i].setImageResource(R.drawable.point_normal);
                        }
                    }
                }

                @Override
                public void onPageScrollStateChanged(int state) {

                }
            });
        }


        private void initPoint() {
            points = new ImageView[imagesUrl.length];
            for(int i=0;i<points.length;i++){
                points[i] = (ImageView) linearlayout.getChildAt(i);
            }
            points[0].setImageResource(R.drawable.point_focus);
        }
    }



    class ItemViewHolder extends RecyclerView.ViewHolder{
        private TextView mTextView;
        public ItemViewHolder(View itemView) {
            super(itemView);
            mTextView = (TextView) itemView.findViewById(R.id.textview);
        }
    }

    class LoadFooterViewHolder extends RecyclerView.ViewHolder{

        private ProgressBar loarmore_progressbar;
        private TextView loadmore_text;
        public LoadFooterViewHolder(View itemView) {
            super(itemView);
            loarmore_progressbar= (ProgressBar) itemView.findViewById(R.id.loarmore_progressbar);
            loadmore_text = (TextView) itemView.findViewById(R.id.loadmore_text);
        }
    }

说明:可以看出,我头部ViewPager的数据全是在内部类中处理的。
中间是列表数据,第3步绑定数据那里处理的,最下面是加载脚View,在上面的绑定数据那里设置了动态的显示不同的加载状态。

OK 这样数据适配器就搞定了!
下拉刷新有谷歌的SwipeRefreshLayout实现了,该如何检测到何时滑到底了需要加载新数据了呢。方法如下:

//向上滑动,当滑到底的时候,有上滑的趋势,就加载更多
        mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if(!mSwipeRefreshLayout.isRefreshing()){
                    if(newState==RecyclerView.SCROLL_STATE_IDLE&&mAdapter.getItemCount()==lastVisibleItem+1){
                        //调用Adapter里的changeMoreStatus方法来改变加载脚View的显示状态为:正在加载...
                        mAdapter.changeMoreStatus(MyRecyclerViewAdapter.ISLOADING);
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                mListData.addAll(mListLoadData);
                                mAdapter.notifyDataSetChanged();
                                //当加载完数据后,再恢复加载脚View的显示状态为:上拉加载更多
                                mAdapter.changeMoreStatus(MyRecyclerViewAdapter.PULLUP_LOAD_MORE);
                            }
                        },3000);
                    }
                }
            }

说明:RecyclerView有一个setOnScrollListener方法,加载更多的逻辑就在这里面实现,具体不说了,看一下就明白了。

MainActivity的完整代码:

package com.example.lenovo.recyclerview;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import Adapter.MyRecyclerViewAdapter;

public class MainActivity extends Activity {
    private RecyclerView mRecyclerView;
    private SwipeRefreshLayout mSwipeRefreshLayout;
    private LinearLayoutManager mManager;
    private MyRecyclerViewAdapter mAdapter;
    private List<String> mListData;
    private List<String> mListLoadData;
    private String[] imagesUrl = {
            "http://bbs.uc.cn/data/attachment/forum/201302/17/163510xsv14x35i9ix41i0.jpg",
            "http://p3.so.qhimg.com/t0121ddd5bc66dcc9e8.jpg",
            "http://p3.so.qhimg.com/t0181e8d7355386f79d.jpg",
            "http://bbs.liebao.cn/data/attachment/forum/201210/25/182447qee2e922myyw8y8m.jpg"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();

        //下拉刷新
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mSwipeRefreshLayout.setRefreshing(false);
                    }
                },2000);
            }
        });

        //当滑到最后一项,还有上滑的趋势,就加载更多
        mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if(!mSwipeRefreshLayout.isRefreshing()){
                    if(newState==RecyclerView.SCROLL_STATE_IDLE&&mAdapter.getItemCount()==lastVisibleItem+1){
                        mAdapter.changeMoreStatus(MyRecyclerViewAdapter.LOADING_MORE);
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                mListData.addAll(mListLoadData);
                                mAdapter.notifyDataSetChanged();
                                mAdapter.changeMoreStatus(MyRecyclerViewAdapter.PULLUP_LOAD_MORE);
                            }
                        },3000);
                    }
                }
                }
            }
        });
    }

    /**
     * 初始化数据
     */
    private void initData() {
        mListData = new ArrayList<>();
        mListLoadData = new ArrayList<>();
        for(int i=0;i<30;i++){
            mListData.add("数据"+i);
            mListLoadData.add("加载的新数据"+i);
        }
    }

    /**
     * 初始化view
     */
    private void initView() {
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        mManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mManager);
        mAdapter = new MyRecyclerViewAdapter(this,mListData,imagesUrl);
        mRecyclerView.setAdapter(mAdapter);
        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swiperefreshlayout);
        //最多可以4种颜色
        mSwipeRefreshLayout.setColorSchemeColors(Color.BLUE,Color.RED);
    }
}

必要的地方都有说明,就不赘述了。搞定!运行!一看效果还是可以的,就下拉刷新 上拉加载玩了一下,当我手动滑动ViewPager的轮播图时候,发现有的不顺畅,下拉刷新有种要被拉下来的感觉,发现有冲突:
百度了一下,发现也有不少人有这个问题,解决办法网上也一大堆:
重写SwipeRefreshLayout。

于是乎,就重写了一下,代码如下:

package View;

import android.content.Context;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;

/**
 * Created by lenovo on 2016/7/9.
 */
public class MySwipeRefreshLayout extends SwipeRefreshLayout {
    private int mTouchSlop;
    // 上一次触摸时的X坐标
    private float mPrevX;
    public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 触发移动事件的最短距离,如果小于这个距离就不触发移动控件
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mPrevX = event.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                final float eventX = event.getX();
                float xDiff = Math.abs(eventX - mPrevX);
                // Log.d("refresh" ,"move----" + eventX + "   " + mPrevX + "   " + mTouchSlop);
                // 增加60的容差,让下拉刷新在竖直滑动时就可以触发
                if (xDiff > mTouchSlop + 60) {
                    return false;
                }
        }
        return super.onInterceptTouchEvent(event);
    }
}

再运行!搞定!完美!!

SwipeRefreshLayout+RecyclerView实现下拉刷新上拉自动加载

标签:

原文地址:http://blog.csdn.net/androidstudioo/article/details/51868223

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!