完全自定义RecyclerView下拉刷新上拉加载

自从谷歌推出SwipeRefreshLayout之后越来越多的博客都是使用SwipeRefreshLayout来完成下拉刷新,但是往往产品经理根本不会使用谷歌的样式.每个公司都有一套自己的下拉样式这个时候就需要我们完全自定义RecyclerView的下拉刷新,基本查阅了网上所有的下拉刷新,但是效果都不怎么样.个人感觉我写的这个下拉刷新效果方面绝对的66666,欢迎可以提出一些改进意见:

 

 

废话不多说 先上效果图:

 

 

RecyclerView 出现以后,Android 里的下拉刷新和加载更多实现起来就非常容易了。当然,现成的库也有很多,只是总会有不一样的需求,而且我们往往只需要最基本的下拉刷新和加载更多功能,而不需要其他多余的功能。我只需要一个最纯粹的下拉刷新和加载更多。所以,自己动手显然是最好的结果了,也算是个小练习

 

在介绍代码之前我们先来讲一下实现原理:

 

首先,我们先通过重写RecyclerView的Adapter类装饰器为起实现addHeaderView,addFootView方法来添加头部与尾部。头部的实现是通过动态的修改的头部控件的高度,尾部的实现是通过动态修改它的BottomMargin,因为尾部的是默认显示的,使用Margin好实现,如果想实现下拉刷新和上拉加载功能,那么就必须有拉伸效果,所以就像上面的那样,Header是通过设置height,Footer是通过设置BottomMargin来模拟拉伸效果。那么回弹效果呢?仅仅通过设置高度或者是间隔是达不到模拟回弹效果的,因此,就需要用Scroller来实现模拟回弹效果。

 

本项目我把它分为主要的五部分HeaderAndFooterWrapper,PullRefreshRecyclerView,RecyclerViewFooter,RecyclerViewHeader,MessageRelativeLayout

 

下面我们分开来介绍。

 

HeaderAndFooterWrapper

 

这个类主要实现了RecyclerView的addHeaderView,addFootView方法,详细资料看参考弘洋大神的Android 优雅的为RecyclerView添加HeaderView和FooterView

 

以下是详细代码:

 

 

/**
 * Created by
 * 公司:
 * 描述:
 */

public class HeaderAndFooterWrapper extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final int BASE_ITEM_TYPE_HEADER = 100000;
    private static final int BASE_ITEM_TYPE_FOOTER = 200000;
    //头集合 尾结合
    private SparseArrayCompat<View> mHeaderViews = new SparseArrayCompat<>();
    private SparseArrayCompat<View> mFootViews = new SparseArrayCompat<>();

    private RecyclerView.Adapter mInnerAdapter;

    /**
     * 把传进来的adapter赋值给成员变量
     *
     * @param adapter
     */
    public HeaderAndFooterWrapper(RecyclerView.Adapter adapter) {
        mInnerAdapter = adapter;
    }

    private boolean isHeaderViewPos(int position) {
        return position < getHeadersCount();
    }

    private boolean isFooterViewPos(int position) {
        return position >= getHeadersCount() + getRealItemCount();
    }

    /**
     * 添加头部方法
     *
     * @param view
     */
    public void addHeaderView(View view) {
        mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, view);
    }

    /**
     * 添加尾部方法
     *
     * @param view
     */
    public void addFootView(View view) {
        mFootViews.put(mFootViews.size() + BASE_ITEM_TYPE_FOOTER, view);
    }

    /**
     * 获取头部集合的大小
     *
     * @return
     */
    public int getHeadersCount() {
        return mHeaderViews.size();
    }

    /**
     * 获取尾部集合的大小
     *
     * @return
     */
    public int getFootersCount() {
        return mFootViews.size();
    }

    /**
     * 获取adapter的大小
     *
     * @return
     */
    private int getRealItemCount() {
        return mInnerAdapter.getItemCount();
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mHeaderViews.get(viewType) != null) {

//            ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), mHeaderViews.get(viewType));
//            return holder;
            return new HeaderViewHolder(mHeaderViews.get(viewType));

        } else if (mFootViews.get(viewType) != null) {
//            ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), mFootViews.get(viewType));
//            return holder;
            return new FootViewHolder(mFootViews.get(viewType));
        }
        return mInnerAdapter.onCreateViewHolder(parent, viewType);
    }

    @Override
    public int getItemViewType(int position) {

        if (isHeaderViewPos(position)) {
            return mHeaderViews.keyAt(position);
        } else if (isFooterViewPos(position)) {
            return mFootViews.keyAt(position - getHeadersCount() - getRealItemCount());
        }
        return mInnerAdapter.getItemViewType(position - getHeadersCount());
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (isHeaderViewPos(position)) {
            return;
        }
        if (isFooterViewPos(position)) {
            return;
        }
        mInnerAdapter.onBindViewHolder(holder, position - getHeadersCount());
    }

    @Override
    public int getItemCount() {
        return getHeadersCount() + getFootersCount() + getRealItemCount();
    }


    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        mInnerAdapter.onAttachedToRecyclerView(recyclerView);

        /**
         * 解决网格布局问题
         */
        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;

            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    int viewType = getItemViewType(position);
                    if (mHeaderViews.get(viewType) != null) {
                        return gridLayoutManager.getSpanCount();
                    } else if (mFootViews.get(viewType) != null) {
                        return gridLayoutManager.getSpanCount();
                    } else {
                        return 1;
                    }
                }
            });
        }
    }

//    /**
//     * 解决 StaggeredGridLayoutManager样式的加头部问题,暂时没用
//     * @param holder
//     */
//    @Override
//    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
//        mInnerAdapter.onViewAttachedToWindow(holder);
//        int position = holder.getLayoutPosition();
//        if (isHeaderViewPos(position) || isFooterViewPos(position)) {
//            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
//
//            if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
//
//                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
//
//                p.setFullSpan(true);
//            }
//        }
//    }


    private class HeaderViewHolder extends RecyclerView.ViewHolder {
        HeaderViewHolder(View itemView) {
            super(itemView);
        }
    }

    private class FootViewHolder extends RecyclerView.ViewHolder {
        FootViewHolder(View itemView) {
            super(itemView);

        }
    }
}

 

 

 

 

 

RecyclerViewHeader

 

RecyclerViewHeader继承自LinearLayout用来实现下拉刷新时的界面展示,可以分为三种状态:正常、准备刷新、正在加载。在添加布局文件的时候,指定高度为0,这是为了隐藏header,setState()是设置header的状态,因为header需要根据不同的状态,完成控件隐藏、显示、改变文字等操作,这个方法主要是在PullRefreshRecyclerView里面调用。除此之外,还有setVisiableHeight()和getVisiableHeight(),这两个方法是为了设置和获取Header中根布局文件的高度属性,从而完成拉伸和收缩的效果

 

 

/**
 * 
 * 
 * 描述:
 */

public class RecyclerViewHeader extends LinearLayout {
    /**
     * 动画执行时间
     */
    private final int ROTATE_ANIM_DURATION = 180;

    public final static int STATE_NORMAL = 0;
    public final static int STATE_READY = 1;
    public final static int STATE_REFRESHING = 2;
    /**
     * 当前状态
     */
    private int mState = STATE_NORMAL;

    //获取到头布局
    private LinearLayout mContainer;
    //获取到控件
    private ImageView mArrowImageView;
    //    private ProgressBar mProgressBar;
    private TextView mHintTextView;
    //初始化动画
//    private RotateAnimation mRotateUpAnim;
//    private Animation mRotateDownAnim;
    private TextView mTitleTextView;
    private RelativeLayout mRealityContent;


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

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

    public RecyclerViewHeader(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init(context);
    }

    private void init(Context context) {
        // 初始情况,设置下拉刷新view高度为0
        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0);
        //获取下拉布局
        mContainer = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.pullrefrefh_recyclerview_header, (ViewGroup) getParent(), true);
        //添加到改容器
        addView(mContainer, lp);
        //显示位置下面
        setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
        //初始化控件
        mRealityContent = (RelativeLayout) mContainer.findViewById(R.id.pullRefresh_reality_content);
        mArrowImageView = (ImageView) mContainer.findViewById(R.id.pullRefresh_arrow);
        mHintTextView = (TextView) mContainer.findViewById(R.id.pullRefresh_text);
//        mProgressBar = (ProgressBar) findViewById(R.id.pullRefresh_progressbar);
        mTitleTextView = (TextView) mContainer.findViewById(R.id.pullRefresh_title);

        //初始化动画
//        mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,
//                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
//                0.5f);
//        mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
//        mRotateUpAnim.setFillAfter(true);
//        mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,
//                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
//                0.5f);
//        mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
//        mRotateDownAnim.setFillAfter(true);
    }

    public void setState(int state) {
        //如果状态相同  直接返回
        if (mState == state) return;

        //如果传进来的是刷新状态
        if (state == STATE_REFRESHING) {    // 正在加载显示圆圈进度
//            mArrowImageView.clearAnimation();
//            mArrowImageView.setVisibility(View.INVISIBLE);
//            mProgressBar.setVisibility(View.VISIBLE);
        } else {    // 显示箭头图片
//            mArrowImageView.setVisibility(View.VISIBLE);
//            mProgressBar.setVisibility(View.INVISIBLE);
        }

        switch (state) {
            case STATE_NORMAL://正常状态
                if (mState == STATE_READY) {
//                    mArrowImageView.startAnimation(mRotateDownAnim);
                }
                if (mState == STATE_REFRESHING) {
//                    mArrowImageView.clearAnimation();
                }
                mHintTextView.setText("下拉刷新");
                break;
            case STATE_READY://可以刷新状态
                if (mState != STATE_READY) {
//                    mArrowImageView.clearAnimation();
//                    mArrowImageView.startAnimation(mRotateUpAnim);
                    mHintTextView.setText("松开刷新数据");
                }
                break;
            case STATE_REFRESHING://刷新状态
                mHintTextView.setText("正在加载...");
                break;
            default:
        }

        mState = state;

    }

    /**
     * 设置显示的图片
     *
     * @param imagePath
     */
    public void setPullImage(String imagePath) {
        Drawable fromPath = Drawable.createFromPath(imagePath);
        Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
//        mArrowImageView.setBackground(fromPath);
        mArrowImageView.setImageBitmap(bitmap);
    }

    /**
     * 设置显示的文字
     *
     * @param text
     */
    public void setPullContent(String text) {
        mTitleTextView.setText(text);

    }

    /**
     * 获取本身实际的高度
     */
    public int getRealityHeight() {
        return mRealityContent.getHeight();
    }


    /**
     * 设置隐藏高度
     *
     * @param height
     */
    public void setVisibleHeight(int height) {
        if (height < 0) {
            height = 0;
        }

        LayoutParams lp = (LayoutParams) mContainer.getLayoutParams();
        lp.height = height;
        mContainer.setLayoutParams(lp);
    }

    /**
     * 获取隐藏的高度
     *
     * @return
     */
    public int getVisibleHeight() {
        return mContainer.getLayoutParams().height;
    }
}

 

 

 

 

 

 

说完了Header,我们再看看Footer。Footer是为了完成加载更多功能时候的界面展示,基本思路和Header是一样的,不过Footer的拉伸和显示效果不是通过高度来模拟的,而是通过设置BottomMargin来完成的。

 

 

 

/**
 * 
 * 公司:
 * 描述:
 */

public class RecyclerViewFooter extends LinearLayout {
    public final static int STATE_NORMAL = 0;
    public final static int STATE_READY = 1;
    public final static int STATE_LOADING = 2;

    private Context context;
    private View contentView;
    private View progressBar;
    private TextView hintView;


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

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

    public RecyclerViewFooter(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        initView();

    }

    private void initView() {
        LinearLayout moreView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.pullrefrefh_recyclerview_footer, null);
        addView(moreView);
        moreView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));

        contentView = moreView.findViewById(R.id.pullrefrefh_footer_content);
        progressBar = moreView.findViewById(R.id.pullrefrefh_footer_ProgressBar);
        hintView = (TextView) moreView.findViewById(R.id.pullrefrefh_footer_hint_TextView);
    }

    /**
     * 设置状态
     *
     * @param state
     */
    public void setState(int state) {
        hintView.setVisibility(View.INVISIBLE);
        progressBar.setVisibility(View.INVISIBLE);
        hintView.setVisibility(View.INVISIBLE);
        if (state == STATE_READY) {
            hintView.setVisibility(View.VISIBLE);
            hintView.setText("松开载入更多");
        } else if (state == STATE_LOADING) {
            progressBar.setVisibility(View.VISIBLE);
        } else {
            hintView.setVisibility(View.VISIBLE);
            hintView.setText("查看更多");
        }
    }

    /**
     * 设置距离下边的BottomMargin
     *
     * @param height
     */
    public void setBottomMargin(int height) {
        if (height < 0) return;
        LayoutParams lp = (LayoutParams) contentView.getLayoutParams();
        lp.bottomMargin = height;
        contentView.setLayoutParams(lp);

    }

    /**
     * 获取BottomMargin
     *
     * @return
     */
    public int getBottomMargin() {
        LayoutParams lp = (LayoutParams) contentView.getLayoutParams();
        return lp.bottomMargin;
    }


    /**
     * hide footer when disable pull load more
     */
    public void hide() {
        LayoutParams lp = (LayoutParams) contentView.getLayoutParams();
        lp.height = 0;
        contentView.setLayoutParams(lp);
    }

    /**
     * show footer
     */
    public void show() {
        LayoutParams lp = (LayoutParams) contentView.getLayoutParams();
        lp.height = LayoutParams.WRAP_CONTENT;
        contentView.setLayoutParams(lp);
    }
}

 

 

 

 

 

MessageRelativeLayout

 

该类主要是为了实现在刷新完毕的时候可以显示一个更新了多少条,网络错误等等的提示语:在添加布局文件的时候,指定高度为0,这是为了隐藏提示语,实现思路与头布局类似,如不需要此功能可忽略,不会影响代码的使用

 

 

/**
 * Created 
 * 公司:
 * 描述:
 */

public class MessageRelativeLayout extends RelativeLayout {

    //显示消息的控件
    private LinearLayout mHeaderMessageView;
    private TextView mHeaderMessageText;


    private int mHeaderMessageViewHeight;
    //滚动类
    private Scroller mScroller;

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

    public MessageRelativeLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MessageRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        init(context);
    }

    private void init(Context context) {
        //滚动类
        mScroller = new Scroller(context, new DecelerateInterpolator());
        //初始化一个显示消息的textView
        mHeaderMessageView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.pullrefresh_header_message, (ViewGroup) getParent(), false);
        mHeaderMessageView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0));

        mHeaderMessageText = (TextView) mHeaderMessageView.findViewById(R.id.pullRefresh_message);

        // 初始化 头部高度
        mHeaderMessageText.getViewTreeObserver().addOnGlobalLayoutListener(
                new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        mHeaderMessageViewHeight = mHeaderMessageText.getHeight();//57

                        getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    }
                });

    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //确保添加到后面
        addView(mHeaderMessageView, 1);
    }

    public void showMessage() {
        mScroller.startScroll(0, getHeaderMessageViewHeight(), 0, 0, PullRefreshRecyclerView.SCROLL_DURATION);
        invalidate();
    }

    public void hideMessage() {
        mScroller.startScroll(0, getVisibleHeight(), 0, -getVisibleHeight(), PullRefreshRecyclerView.SCROLL_DURATION);
        invalidate();
    }


    /**
     * 设置消息
     */
    public void setMessage(String message) {
        mHeaderMessageText.setText(message);

    }


    /**
     * 获取消息总高度
     *
     * @return
     */
    public int getHeaderMessageViewHeight() {
        return mHeaderMessageViewHeight;
    }

    /**
     * 设置隐藏高度
     *
     * @param height
     */
    private void setVisibleHeight(int height) {
        if (height < 0) {
            height = 0;
        }

       LayoutParams lp = (LayoutParams) mHeaderMessageView.getLayoutParams();
        lp.height = height;
        mHeaderMessageView.setLayoutParams(lp);
    }

    /**
     * 获取隐藏的高度
     *
     * @return
     */
    public int getVisibleHeight() {
        return mHeaderMessageView.getLayoutParams().height;
    }
    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {

                setVisibleHeight(mScroller.getCurrY());

            postInvalidate();
        }
        super.computeScroll();
    }
}

 

 

 

 

 

PullRefreshRecyclerView

 

在了解了Header,Footer和Message之后,我们就要介绍最核心的PullRefreshRecyclerView的代码实现了。便于观看,本代码有部分删减重构

 

 

/**
 * Created
 * 公司
 * 描述:
 */

public class PullRefreshRecyclerView extends RecyclerView {

    private float mLastY = -1; // save event y
    /**
     * 滚动需要的时间
     */
    public final static int SCROLL_DURATION = 200;

    /**
     * 提示消息显示时间
     */
    public final static int MESSAGE_SHOW_DURATION = 2000;
    /**
     * 阻尼效果
     */
    private final static float OFFSET_RADIO = 1.5f;
    /**
     * 上拉加载的距离,默认50px
     */
    private static final int PULL_LOAD_MORE_DELTA = 50;

    /**
     * 是否设置为自动加载更多,目前没实现
     */
    private boolean mEnableAutoLoading = false;
    /**
     * 是否可以上拉  默认可以
     */
    private boolean mEnablePullLoad = true;
    /**
     * 是否可以下拉   默认可以
     */
    private boolean mEnablePullRefresh = true;
    /**
     * 是否正在加载
     */
    private boolean mPullLoading = false;
    /**
     * 是否正在刷新
     */
    private boolean mPullRefreshing = false;
    /**
     * 区分上拉和下拉
     */
    private int mScrollBack;
    private final static int SCROLLBACK_HEADER = 0;
    private final static int SCROLLBACK_FOOTER = 1;
    //滚动类
    private Scroller mScroller;

    //头布局控件
    private RecyclerViewHeader mHeaderView;
    //尾控件
    private RecyclerViewFooter mFooterView;
    //消息提示类
    private MessageRelativeLayout mParent;
    //adapter的装饰类
    private HeaderAndFooterWrapper mHeaderAndFooterWrapper;


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

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

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

    private void init(Context context) {
        //滚动类
        mScroller = new Scroller(context, new DecelerateInterpolator());
        //获取到头布局
        mHeaderView = new RecyclerViewHeader(context);
        mHeaderView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        //获取尾布局
        mFooterView = new RecyclerViewFooter(context);
        mFooterView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));

    }


    private Adapter adapter;

    @Override
    public void setAdapter(Adapter adapter) {
        this.adapter = adapter;
        mHeaderAndFooterWrapper = new HeaderAndFooterWrapper(adapter);

        super.setAdapter(mHeaderAndFooterWrapper);

        //添加头,确保是第一个
        mHeaderAndFooterWrapper.addHeaderView(mHeaderView);
        //添加尾,确保是第最后一个
        mHeaderAndFooterWrapper.addFootView(mFooterView);
        //获取到它的父容器
        if (getParent() instanceof MessageRelativeLayout) {
            mParent = (MessageRelativeLayout) getParent();
        }
    }


    @Override
    public boolean onTouchEvent(MotionEvent e) {
        if (mLastY == -1) {
            mLastY = e.getRawY();
        }
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //按下的时候记录值
                mLastY = e.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:


                float moveY = e.getRawY();
                //手指滑动的差值
                float distanceY = moveY - mLastY;
                mLastY = moveY;

                //第一个条目完全显示   //头部高度大于0   deltaY大于0  向下移动
                if ((((LinearLayoutManager) getLayoutManager()).findFirstCompletelyVisibleItemPosition() == 0 || ((LinearLayoutManager) getLayoutManager()).findFirstCompletelyVisibleItemPosition() == 1) && (mHeaderView.getVisibleHeight() > 0 || distanceY > 0)) {
                    // 更新头部高度
                    updateHeaderHeight(distanceY / OFFSET_RADIO);
                } else if (isSlideToBottom() && (mFooterView.getBottomMargin() > 0 || distanceY < 0)) {
                    Log.e("PullRefreshRecyclerView","-------111------"+distanceY);
                    //已经到达底部,改变状态或者自动加载
                    updateFooterHeight(-distanceY / OFFSET_RADIO);
                }else if (distanceY > 0){
                    updateFooterHeight(-distanceY / OFFSET_RADIO);
                }

                break;
            default:
                mLastY = -1; // 复位
                if ((((LinearLayoutManager) getLayoutManager()).findFirstCompletelyVisibleItemPosition() == 0 || ((LinearLayoutManager) getLayoutManager()).findFirstCompletelyVisibleItemPosition() == 1)) {
                    // 松手的时候  高度大于  一定值  调用刷新
                    if (mEnablePullRefresh && mHeaderView.getVisibleHeight() > mHeaderView.getRealityHeight()) {
                        //变为刷新状态
                        mPullRefreshing = true;
                        mHeaderView.setState(RecyclerViewHeader.STATE_REFRESHING);
                        //回调事件
                        if (mOnRefreshListener != null) {
                            mOnRefreshListener.onRefresh();
                        }
                    }
                    resetHeaderHeight();
                } else if (isSlideToBottom()) {
                    // invoke load more.
                    if (mEnablePullLoad && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA && !mPullLoading) {
                        mPullLoading = true;
                        mFooterView.setState(RecyclerViewFooter.STATE_LOADING);
                        if (mOnRefreshListener != null) {
                            mOnRefreshListener.onLoadMore();
                        }

                    }
                    resetFooterHeight();
                } else {
//                    resetFooterHeight();
                    resetHeaderHeight();
                }

                break;
        }


        return super.onTouchEvent(e);
    }

    /**
     * 更新尾部加载
     *
     * @param distance
     */
    private void updateFooterHeight(float distance) {
        int height = mFooterView.getBottomMargin() + (int) distance;
        Log.e("PullRefreshRecyclerView","-------------"+height);
        if (mEnablePullLoad && !mPullLoading) {
            if (height > PULL_LOAD_MORE_DELTA) {
                //改变状态
                mFooterView.setState(RecyclerViewFooter.STATE_READY);
            } else {
                mFooterView.setState(RecyclerViewFooter.STATE_NORMAL);
            }
        }
        mFooterView.setBottomMargin(height);

    }

    /**
     * 更新头部刷新
     *
     * @param distance
     */
    private void updateHeaderHeight(float distance) {

        // 设置头部高度,原先的高度加上
        mHeaderView.setVisibleHeight((int) distance + mHeaderView.getVisibleHeight());
        // 未处于刷新状态,更新箭头
        if (mEnablePullRefresh && !mPullRefreshing) {
            //下拉高度到达可以刷新的位置
            if (mHeaderView.getVisibleHeight() > mHeaderView.getRealityHeight()) {
                mHeaderView.setState(RecyclerViewHeader.STATE_READY);
            } else {
                mHeaderView.setState(RecyclerViewHeader.STATE_NORMAL);
            }
        }
        //移动到顶部
        smoothScrollBy(0, 0);
    }

    /**
     * 重置头部高度
     */
    private void resetHeaderHeight() {
        int height = mHeaderView.getVisibleHeight();
        if (height == 0) // 如果=0  是不可见的 直接返回
            return;

        if (mPullRefreshing && height <= mHeaderView.getRealityHeight()) {
            return;
        }

        int finalHeight = 0;

        if (mPullRefreshing && height > mHeaderView.getRealityHeight()) {
            finalHeight = mHeaderView.getRealityHeight();
        }
        if (mParent != null) {
            if (mHeaderView.getVisibleHeight() == mParent.getHeaderMessageViewHeight()) {
                finalHeight = mParent.getHeaderMessageViewHeight();
            }
        }

        mScrollBack = SCROLLBACK_HEADER;//设置标识
        mScroller.startScroll(0, height, 0, finalHeight - height, SCROLL_DURATION);
        // 触发计算滚动
        invalidate();
    }

    /**
     * 重置尾部高度
     */
    private void resetFooterHeight() {
        int bottomMargin = mFooterView.getBottomMargin();
        if (bottomMargin > 0) {
            mScrollBack = SCROLLBACK_FOOTER;//设置标识
            mScroller.startScroll(0, bottomMargin, 0, -bottomMargin, SCROLL_DURATION);
            invalidate();
        }
    }

    /**
     * 停止刷新
     */
    public void stopRefresh() {
        mScrollBack = SCROLLBACK_HEADER;//设置标识
        int obligateHeight;
        if (mParent != null) {
            obligateHeight = mParent.getHeaderMessageViewHeight();
        } else {
            obligateHeight = 0;
        }
        int height = mHeaderView.getVisibleHeight();
        if (mPullRefreshing) {
            //是否复位

            mPullRefreshing = false;

            //显示更新了多少条消息
            if (mParent != null) {
                mParent.showMessage();
            }
            mScroller.startScroll(0, height, 0, obligateHeight - height, SCROLL_DURATION);
            // 触发计算滚动
            invalidate();

            //延时执行复位移动
            if (mParent != null) {
                handler.removeCallbacksAndMessages(null);
                handler.sendEmptyMessageDelayed(1, MESSAGE_SHOW_DURATION);
            }
        }

    }

    /**
     * 停止加载
     */
    public void stopLoadMore() {
        if (mPullLoading) {
            mPullLoading = false;
            mFooterView.setState(RecyclerViewFooter.STATE_NORMAL);
        }
    }

    /**
     * 消息
     */
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (mHeaderView.getVisibleHeight() == mParent.getHeaderMessageViewHeight()) {
//                resetHeaderHeight();
                mScroller.startScroll(0, mHeaderView.getVisibleHeight(), 0, -mHeaderView.getVisibleHeight(), SCROLL_DURATION);
                postInvalidate();
            }

            mParent.hideMessage();
        }
    };

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            if (mScrollBack == SCROLLBACK_HEADER) {
                mHeaderView.setVisibleHeight(mScroller.getCurrY());
            } else {
                mFooterView.setBottomMargin(mScroller.getCurrY());
            }
            postInvalidate();
        }
        super.computeScroll();
    }

    private OnRefreshListener mOnRefreshListener;

    public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
        mOnRefreshListener = onRefreshListener;
    }

    /**
     * 刷新接口,
     */
    public interface OnRefreshListener {
        void onRefresh();

        void onLoadMore();
    }

    /**
     * 判断是否到底
     *
     * @return
     */
    private boolean isSlideToBottom() {
        return computeVerticalScrollExtent() + computeVerticalScrollOffset() >= computeVerticalScrollRange();
    }
}

 

 

 

 

 

 

最后重要的事说三遍:本项目扩展性极高,建议下载源码观看可更清晰的了解此项目的结构

 

源码地址:http://download.csdn.net/download/q714093365/9928217

 

转载请注明出处:http://blog.csdn.net/q714093365/article/details/77063084

 

 

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值