天天看点

Android之RecyclerView轻松实现下拉刷新和加载更多

今天研究了下RecyclerView的滑动事件,特别是下拉刷新和加载更多事件,在现在几乎所有的APP显示数据列表时都用到了。自定义RecyclerView下拉刷新和加载更多听上去很复杂,实际上并不难,只要是对滑动事件的监听和处理。

一、自定义RecyclerView实现下拉刷新和加载更多

1、如何判断RecyclerView是在上滑还是下滑

在RecyclerView的OnScrollListener滑动事件监听中有个好用的方法,就是onScrolled(RecyclerView recyclerView, int dx, int dy),其中根据dx的值的正负就可以判断是在左滑还是右滑,而根据dy的值就可以判断是在上滑还是下滑。

//上滑
if(dy>0){
//相应操作代码
}
//下滑
else if(dy<0){
//相应操作代码
}
           

2、如何判断是否滑到了顶部或者底部

同样在RecyclerView的OnScrollListener滑动事件监听中onScrolled(RecyclerView recyclerView, int dx, int dy)方法中处理,根据canScrollVertically(int direction)来进行判断。

//是否滑到底部
if(!recyclerView.canScrollVertically(1)){
    //相应处理操作
}
//是否滑到顶部
if(!recyclerView.canScrollVertically(-1)){
    //相应处理操作
}
           

3、自定义RecyclerView

知道了滑动事件的判断和处理,就可以很轻松得实现下拉刷新和加载更多了。

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * Package:com.liuting.library
 * author:liuting
 * Date:2017/2/14
 * Desc:自定义RecycleView,下拉刷新以及上拉加载更多
 */

public class RefreshLoadMoreRecycleView extends RecyclerView implements RecyclerView.OnTouchListener{
    private Boolean isLoadMore;//加载更多标志
    private Boolean isLoadEnd;//加载到最后的标志
    private Boolean isLoadStart;//顶部的标志
    private Boolean isRefresh;//下拉刷新标志
    private int lastVisibleItem;//最后一项
    private IOnScrollListener listener;//事件监听
    private float mLastY;//监听移动的位置

    public RefreshLoadMoreRecycleView(Context context) {
        super(context);
        init(context);
    }

    public RefreshLoadMoreRecycleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

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

	 /**
     * 初始化
     * 
     * @param context
     */
    public void init(Context context) {
        isLoadEnd=false;
        isLoadStart =true;

        this.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                //SCROLL_STATE_DRAGGING  和   SCROLL_STATE_IDLE 两种效果自己看着来
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    loadData();
                }
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                //上滑
                if(dy>0){
                    //是否滑到底部
                    if(!recyclerView.canScrollVertically(1)){
                        isLoadEnd = true;
                    }else{
                        isLoadEnd = false;
                    }
                    Log.e("TAG","Running--->>isLoadEnd:"+isLoadEnd+dy);
                }else if(dy<0){
                    //是否滑到顶部
                    if(!recyclerView.canScrollVertically(-1)){
                        isLoadStart=true;
                    }else{
                        isLoadStart=false;
                    }

                }
            }
        });
        this.setOnTouchListener(this);
    }

	 /**
     * 
     * 加载数据
     * 
     */
    private void loadData() {
        if (isLoadEnd) {
            // 判断是否已加载所有数据
            if (isLoadMore) {//未加载完所有数据,加载数据,并且还原isLoadEnd值为false,重新定位列表底部
                if (getListener() != null) {
                    getListener().onLoadMore();
                }
            } else {//加载完了所有的数据
                if(getListener()!=null){
                    getListener().onLoaded();
                }
            }
            isLoadEnd = false;
        } else if (isLoadStart) {
            if(isRefresh){
                if (getListener() != null) {
                    getListener().onRefresh();
                }
                isLoadStart=false;
            }
        }
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (mLastY == -1) {
            mLastY = motionEvent.getRawY();
        }
        switch (motionEvent.getAction()){
            case MotionEvent.ACTION_MOVE:
                final float deltaY = motionEvent.getRawY() - mLastY;
                mLastY = motionEvent.getRawY();
				//向上移动
                if(deltaY<0){
                    //是否滑到底部
                    if(!this.canScrollVertically(1)){
                        isLoadEnd = true;
                    }else{
                        isLoadEnd = false;
                    }
                }
				//向下移动
				else if(deltaY>0) {
                    //是否滑到顶部
                    if (!this.canScrollVertically(-1)) {
                        isLoadStart = true;
                    } else {
                        isLoadStart = false;
                    }
                }
                break;
            case MotionEvent.ACTION_DOWN:
                mLastY = motionEvent.getRawY();
                break;
            default://重置
                mLastY = -1;
                break;
        }

        return false;
    }

	//事件监听
    public interface IOnScrollListener {
        void onRefresh();

        void onLoadMore();

        void onLoaded();
    }

    public IOnScrollListener getListener() {
        return listener;
    }

	//设置事件监听
    public void setListener(IOnScrollListener listener) {
        this.listener = listener;
    }

    public Boolean getLoadMore() {
        return isLoadMore;
    }

	//设置是否支持加载更多
    public void setLoadMoreEnable(Boolean loadMore) {
        isLoadMore = loadMore;
    }

    public Boolean getRefresh() {
        return isRefresh;
    }

	//设置是否支持下拉刷新
    public void setRefreshEnable(Boolean refresh) {
        isRefresh = refresh;
    }
}
           

二、实际用例

已经定义好了RecyclerView,下面在Demo中实际使用和处理。

1、定义布局

布局文件很简单,就是一个RecyclerView

2、定义RecyclerView.Adapter

RecyclerView.Adapter在这里就简单处理了,列表布局直接使用Android自带的。

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

/**
 * Package:com.liuting.refreshloadmorelistview.adapter
 * author:liuting
 * Date:2017/2/16
 * Desc:列表Adapter
 */

public class RefreshLoadMoreRecycleAdapter extends RecyclerView.Adapter
      
        {
    private List
       
         list;
    private Context context;

    public RefreshLoadMoreRecycleAdapter(Context context,List
        
          list) {
        this.context =context;
        this.list = list;
    }

    @Override
    public RefreshLoadMoreRecycleAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_expandable_list_item_1, parent, false);
        RefreshLoadMoreRecycleAdapter.ViewHolder viewHolder = new RefreshLoadMoreRecycleAdapter.ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.text.setText(list.get(position));
        holder.itemView.setTag(position);
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder{
        private TextView text;

        public ViewHolder(View itemView) {
            super(itemView);
            text=(TextView)itemView.findViewById(android.R.id.text1);
        }
    }
}
        
       
      
           

3、在Activity中定义好控件以及数据加载操作

实现自定义RecyclerView中的数据加载事件监听,刷新、加载更多以及加载完成。

import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.widget.Toast;

import com.liuting.library.RefreshLoadMoreRecycleView;
import com.liuting.refreshloadmorelistview.adapter.RefreshLoadMoreRecycleAdapter;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements RefreshLoadMoreRecycleView.IOnScrollListener{
    private RefreshLoadMoreRecycleView recycleView;//下拉刷新RecycleView
    private List
       
         list;//列表
    private RefreshLoadMoreRecycleAdapter adapter;//Adapter
    private ProgressDialog dialog;//提示框
    private static final int REFRESH_Load=0;//下拉刷新
    private static final int MORE_Load=1;//加载更多
    private Handler handler =new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case REFRESH_Load:
                    recycleView.setLoadMoreEnable(true);
                    dismissDialog();
                    if(list!=null){
                        list.clear();
                    }
                    loadData();
                    adapter.notifyDataSetChanged();
                    break;
                case MORE_Load:
                    recycleView.setLoadMoreEnable(false);
                    dismissDialog();
                    loadData();
                    adapter.notifyDataSetChanged();
                    break;
            }
        }
    };

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

    public void initView(){
        dialog = new ProgressDialog(MainActivity.this);

        list=new ArrayList<>();
        loadData();
        recycleView = (RefreshLoadMoreRecycleView)findViewById(R.id.main_recycle_view_data);

        final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MainActivity.this);
        recycleView.setLayoutManager(linearLayoutManager);
        adapter = new RefreshLoadMoreRecycleAdapter(MainActivity.this,list);
        recycleView.setAdapter(adapter);
        recycleView.setListener(this);
        recycleView.setRefreshEnable(true);
        recycleView.setLoadMoreEnable(true);
    }

    /**
     * 加载数据
     */
    public void loadData(){
        for(int i=0;i<10;i++ ){
            list.add("It is "+i);
        }
    }

    @Override
    public void onRefresh() {
        showDialog();
        new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    sleep(5000);
                    handler.sendEmptyMessage(REFRESH_Load);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    @Override
    public void onLoadMore() {
        showDialog();
        new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    sleep(5000);
                    handler.sendEmptyMessage(MORE_Load);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    @Override
    public void onLoaded() {
        Toast.makeText(MainActivity.this,"Loaded all",Toast.LENGTH_SHORT).show();
    }

    /**
     * dismiss dialog
     */
    private void dismissDialog(){
        if (dialog!=null&&dialog.isShowing()){
            dialog.dismiss();
        }
    }

    /**
     * show dialog
     */
    private void showDialog(){
        if (dialog!=null&&!dialog.isShowing()){
            dialog.show();
        }
    }
}
       
           

三、最终效果图

Android之RecyclerView轻松实现下拉刷新和加载更多

到这里就轻松实现了RecyclerView的下拉刷新和加载更多了。

源代码在Github上:https://github.com/LT5505/RefreshLoadMoreRecycleView