Android开发 封装向上拉动加载更多RecyclerView

前言

  在很早以前在本人的博客 https://www.cnblogs.com/guanxinjing/p/10299889.html  提供了用RecyclerView实现上拉加载数据的思维,但是用这个方式实现后,每一个上拉加载页面几乎都需要重写大量重复代码。所以进行了重新的封装,以方便使用并且减少重复代码量。如果刚点击这个博客建议看看之前的博客,之前的博客实现思路比较,清晰讲解部分也比较多。

封装后的RecyclerView

使用时请注意,这里以内部类的形式封装了适配器,请使用这里封装的适配器配合一起使用。

package net.wt.gate.ui.widget;

import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.recyclerview.widget.RecyclerView;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.SOURCE;


public class UpLoadingRecyclerView extends RecyclerView {
    private boolean isScroll;
    private float downY;
    private int mHeightPixels;
    private OnUpScrollListener mOnUpScrollListener;
    private OnUpPullLoadListener mOnUpPullLoadListener;

    public UpLoadingRecyclerView(@NonNull Context context) {
        super(context);
        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        mHeightPixels = displayMetrics.heightPixels;
    }

    public UpLoadingRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        mHeightPixels = displayMetrics.heightPixels;
    }

    public UpLoadingRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        mHeightPixels = displayMetrics.heightPixels;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    /**
     * 重写拦截的目的是只拦截移动事件,不拦截其他触摸事件
     *
     * @param e
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        super.onInterceptTouchEvent(e);//一定要super.onInterceptTouchEvent(e);不要让RecyclerView的其他事件分发受到影响,否则会出现不滚动的问题
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isScroll = false;//按下不拦截
                downY = e.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (Math.abs(downY - e.getY()) >= ViewConfiguration.get(
                        getContext()).getScaledTouchSlop()) {//判断是否产生了最小滑动
                    isScroll = true;//移动了拦截触摸事件
                } else {
                    isScroll = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                isScroll = false;//松开不拦截
                break;
        }

        return isScroll;
    }


    @Override
    public boolean onTouchEvent(MotionEvent e) {
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                return true;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                if (downY - e.getY() > mHeightPixels / 5) {//判断是不是从下往上滑动了屏幕的三分之一
                    if (mOnUpScrollListener != null) {
                        mOnUpScrollListener.onScroll();
                    }
                    if (getAdapter() != null && mOnUpPullLoadListener != null && getAdapter() instanceof Adapter) {
                        UpLoadingRecyclerView.Adapter adapter = (UpLoadingRecyclerView.Adapter) getAdapter();
                        if (adapter.isFooterPullUpLoading() && adapter.isFooterItemPosition()) {
                            mOnUpPullLoadListener.OnUpPullLoad();
                        }
                    }

                }
                break;

        }
        return super.onTouchEvent(e);
    }

    public void setOnUpScrollListener(OnUpScrollListener listener) {
        this.mOnUpScrollListener = listener;

    }

    public void setOnUpPullLoadListener(OnUpPullLoadListener onUpPullLoadListener) {
        this.mOnUpPullLoadListener = onUpPullLoadListener;
    }

    public interface OnUpScrollListener {
        void onScroll();

    }

    public interface OnUpPullLoadListener {
        void OnUpPullLoad();
    }

    public static abstract class Adapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter {
        private static final int FOOTER_VIEW = -101;
        private int currentFooterStatus = FooterStatus.FOOTER_NO_MORE_DATA;  //当前页角item状态
        private int scrollPosition;                                          //滚动位置


        public abstract RecyclerView.ViewHolder onCreateItemViewHolder(@NonNull ViewGroup parent, int viewType);

        public abstract RecyclerView.ViewHolder onCreateFooterViewHolder(@NonNull ViewGroup parent);

        public abstract void onBindItemViewHolder(@NonNull RecyclerView.ViewHolder holder, int position);

        public abstract void onBindFooterViewHolder(@NonNull RecyclerView.ViewHolder holder, @FooterStatus int currentFooterStatus);

        public abstract int getItemViewCount();

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            if (viewType != FOOTER_VIEW) {
                return onCreateItemViewHolder(parent, viewType);
            }
            return onCreateFooterViewHolder(parent);
        }


        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            scrollPosition = position;
            if (getItemViewType(position) != FOOTER_VIEW) {
                onBindItemViewHolder(holder, position);
                return;
            }
            onBindFooterViewHolder(holder, currentFooterStatus);
        }


        /**
         * 是否是最后位置
         *
         * @return
         */
        public boolean isFooterItemPosition() {
            return scrollPosition == getItemCount() - 1;
        }

        @Override
        public int getItemViewType(int position) {
            if (getItemCount() != 0 && position == getItemCount() - 1) {
                return FOOTER_VIEW;
            }
            return super.getItemViewType(position);
        }

        @Override
        public int getItemCount() {
            return getItemViewCount() == 0 ? 0 : getItemViewCount() + 1;
        }

        /**
         * 修改页脚状态为加载中
         */
        public void setFooterLoading() {
            currentFooterStatus = FooterStatus.FOOTER_LOADING;
            notifyDataSetChanged();
        }

        /**
         * 修改页脚状态为网络异常
         */
        public void setFooterNetWorkError() {
            currentFooterStatus = FooterStatus.FOOTER_ERROR;
            notifyDataSetChanged();
        }

        /**
         * 修改页脚状态为没有更多数据
         */
        public void setFooterNoMoreData() {
            currentFooterStatus = FooterStatus.FOOTER_NO_MORE_DATA;
            notifyDataSetChanged();
        }

        /**
         * 修改页脚状态为上拉加载数据
         */
        public void setFooterPullUpLoading() {
            currentFooterStatus = FooterStatus.FOOTER_PULL_UP_LOADING;
            notifyDataSetChanged();
        }

        public boolean isFooterLoading() {
            return currentFooterStatus == FooterStatus.FOOTER_LOADING;
        }

        public boolean isFooterNetWorkError() {
            return currentFooterStatus == FooterStatus.FOOTER_ERROR;
        }

        public boolean isFooterNoMoreData() {
            return currentFooterStatus == FooterStatus.FOOTER_NO_MORE_DATA;
        }

        public boolean isFooterPullUpLoading() {
            return currentFooterStatus == FooterStatus.FOOTER_PULL_UP_LOADING;
        }

        /**
         * 创建使用简单页尾
         * @param parent
         * @param viewType
         * @param textSize
         * @param textColor
         * @return
         */
        public RecyclerView.ViewHolder createSimpleFooterView(@NonNull ViewGroup parent, int viewType, float textSize, @ColorInt int textColor) {
            if (viewType == Adapter.FOOTER_VIEW) {
                TextView textView = new TextView(parent.getContext());
                textView.setTextSize(dip2px(parent.getContext(), 14));
                textView.setTextColor(Color.parseColor("#999999"));
                textView.setGravity(Gravity.CENTER);
                ViewGroup.LayoutParams layoutParams = textView.getLayoutParams();
                layoutParams.height = dip2px(parent.getContext(), 30);
                layoutParams.width = LayoutParams.MATCH_PARENT;
                textView.setLayoutParams(layoutParams);
                return new SimpleFooterViewHolder(textView);

            }
            return null;
        }

        /**
         * 绑定简单页尾的ViewHolder
         * @param holder
         * @param position
         * @param pullUpLoadingText
         * @param loadingText
         * @param errorText
         * @param notMoreDataText
         */
        public void bindSimpleFooterViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @StringRes int pullUpLoadingText, @StringRes int loadingText, @StringRes int errorText, @StringRes int notMoreDataText) {
            if (holder instanceof SimpleFooterViewHolder) {
                switch (currentFooterStatus) {
                    case FooterStatus.FOOTER_PULL_UP_LOADING:
                        ((SimpleFooterViewHolder) holder).footerTextView.setText(pullUpLoadingText);
                        break;
                    case FooterStatus.FOOTER_LOADING:
                        ((SimpleFooterViewHolder) holder).footerTextView.setText(loadingText);
                        break;
                    case FooterStatus.FOOTER_ERROR:
                        ((SimpleFooterViewHolder) holder).footerTextView.setText(errorText);
                        break;
                    case FooterStatus.FOOTER_NO_MORE_DATA:
                        ((SimpleFooterViewHolder) holder).footerTextView.setText(notMoreDataText);
                        break;
                    default:
                        break;
                }
            }
        }

        public static class SimpleFooterViewHolder extends RecyclerView.ViewHolder {
            TextView footerTextView;

            public SimpleFooterViewHolder(@NonNull View itemView) {
                super(itemView);
                footerTextView = (TextView) itemView;
            }
        }

    }


    @Retention(SOURCE)
    @Target({PARAMETER})
    @IntDef(value = {FooterStatus.FOOTER_PULL_UP_LOADING, FooterStatus.FOOTER_LOADING, FooterStatus.FOOTER_ERROR, FooterStatus.FOOTER_NO_MORE_DATA})
    public @interface FooterStatus {
        int FOOTER_PULL_UP_LOADING = 0;             //提示上拉加载更多
        int FOOTER_LOADING = 1;                     //加载中
        int FOOTER_ERROR = 2;                       //网络异常
        int FOOTER_NO_MORE_DATA = 3;                //没有更多内容
    }

    /**
     * 根据手机分辨率从DP转成PX
     *
     * @param context
     * @param dpValue
     * @return
     */
    private static int dip2px(Context context, float dpValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

}
原文地址:https://www.cnblogs.com/guanxinjing/p/13204403.html