美文网首页
RecyclerView+BGARefreshLayout实现自

RecyclerView+BGARefreshLayout实现自

作者: smallestt | 来源:发表于2018-02-01 09:03 被阅读0次

    实现方式:

    • 资源准备
      上拉或者下拉时出现的headerview与footerview
      header_bga_dodo.xml :下拉刷新时出现的view
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">
    
        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="15dp"
            android:layout_marginRight="10dip"
            android:layout_marginTop="15dp">
    
            <!-- android:src="@mipmap/refresh_head_arrow" -->
            <ImageView
                android:id="@+id/iv_normal_refresh_header_arrow"
                android:layout_width="28dp"
                android:layout_height="28dp"
                android:layout_gravity="center"
                android:src="@mipmap/default_ptr_wodfan_frame1" />
    
            <ImageView
                android:id="@+id/iv_normal_refresh_header_chrysanthemum"
                android:visibility="invisible"
                android:layout_width="34dp"
                android:layout_height="34dp"
                android:src="@anim/header_dodo_bga_refresh_loading"/>
        </FrameLayout>
    
        <TextView
            android:id="@+id/tv_normal_refresh_header_status"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="15dp"
            android:layout_marginTop="15dp"
            android:text="下拉刷新"
            android:textColor="#777"
            android:textSize="12sp" />
    </LinearLayout>
    

    footer_bga_dodo.xml:上拉加载更多时出现的view

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">
    
        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="15dp"
            android:layout_marginRight="10dip"
            android:layout_marginTop="15dp">
    
            <ImageView
                android:id="@+id/iv_normal_refresh_footer_chrysanthemum"
                android:layout_width="34dp"
                android:layout_height="34dp"
                android:src="@anim/header_dodo_bga_refresh_loading"/>
        </FrameLayout>
    
        <TextView
            android:id="@+id/tv_normal_refresh_footer_status"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="15dp"
            android:layout_marginTop="15dp"
            android:text="加载中..."
            android:textColor="#777"
            android:textSize="12sp" />
    </LinearLayout>
    

    headerview或者footerview里进度条的动画:header_dodo_bga_refresh_loading.xml

    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot="false" >
        <item
            android:drawable="@mipmap/default_ptr_wodfan_frame1"
            android:duration="200"/>
        <item
            android:drawable="@mipmap/default_ptr_wodfan_frame2"
            android:duration="200"/>
    </animation-list>
    

    attrs.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="PowerfulRecyclerView">
            <attr name="dividerColor" format="color"/>
            <attr name="dividerSize" format="dimension"/>
            <attr name="dividerDrawable" format="reference"/>
            <attr name="useStaggerLayout" format="boolean"/>
            <attr name="numColumns" format="integer"/>
            <attr name="rvOrientation" format="enum">
                <enum name="HORIZONTAL" value="0"/>
                <enum name="VERTICAL" value="1"/>
            </attr>
            <attr name="dividerMarginLeft" format="dimension"/>
            <attr name="dividerMarginRight" format="dimension"/>
        </declare-styleable>
        <!--显示提示的View-->
        <declare-styleable name="TipView">
            <attr name="tipBackgroundColor" format="color"/>
            <attr name="tipTextColor" format="color"/>
            <attr name="tipText" format="string"/>
            <attr name="tipTextSize" format="dimension"/>
        </declare-styleable>
    </resources>
    
    • 工具类准备
      dp、sp 转换为 px 的工具类
    /**
     * dp、sp 转换为 px 的工具类
     *
     * @author wangtt
     *
     */
    public class UnitConverterTools {
        /**
         * 将px值转换为dip或dp值,保证尺寸大小不变
         *
         * @param pxValue
         *            (DisplayMetrics类中属性density)
         * @return
         */
        public static int px2dip(Context context, float pxValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (pxValue / scale + 0.5f);
        }
    
        /**
         * 将dip或dp值转换为px值,保证尺寸大小不变
         *
         * @param dipValue
         *            (DisplayMetrics类中属性density)
         * @return
         */
        public static int dip2px(Context context, float dipValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dipValue * scale + 0.5f);
        }
    
        /**
         * 将px值转换为sp值,保证文字大小不变
         *
         * @param pxValue
         *            (DisplayMetrics类中属性scaledDensity)
         * @return
         */
        public static int px2sp(Context context, float pxValue) {
            final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
            return (int) (pxValue / fontScale + 0.5f);
        }
    
        /**
         * 将sp值转换为px值,保证文字大小不变
         *
         * @param spValue
         *            (DisplayMetrics类中属性scaledDensity)
         * @return
         */
        public static int sp2px(Context context, float spValue) {
            final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
            return (int) (spValue * fontScale + 0.5f);
        }
    
        /*
         * double保留小数点后两位
         */
        public static double round(Double v, int scale) {
            if (scale < 0) {
                throw new IllegalArgumentException(
                        "The scale must be a positive integer or zero");
            }
    
            BigDecimal b = null == v ? new BigDecimal("0.0") : new BigDecimal(
                    Double.toString(v));
            BigDecimal one = new BigDecimal("1");
            return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
        }
    
    }
    

    BGANormalRefreshViewHolder.java

    /**
     * wangtt
     * 15/5/21 13:05
     * 类似新浪微博下拉刷新风格
     */
    public class BGANormalRefreshViewHolder extends BGARefreshViewHolder {
        private TextView mHeaderStatusTv;
        private ImageView mHeaderArrowIv;
        private ImageView mHeaderChrysanthemumIv;
        private AnimationDrawable mHeaderChrysanthemumAd;
        private RotateAnimation mUpAnim;
        private RotateAnimation mDownAnim;
    
        private String mPullDownRefreshText = "下拉刷新";
        private String mReleaseRefreshText = "释放更新";
        private String mRefreshingText = "加载中...";
    
        /**
         * @param context
         * @param isLoadingMoreEnabled 上拉加载更多是否可用
         */
        public BGANormalRefreshViewHolder(Context context, boolean isLoadingMoreEnabled) {
            super(context, isLoadingMoreEnabled);
            initAnimation();
        }
    
        private void initAnimation() {
            mUpAnim = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            mUpAnim.setDuration(150);
            mUpAnim.setFillAfter(true);
    
            mDownAnim = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            mDownAnim.setFillAfter(true);
        }
    
        /**
         * 设置未满足刷新条件,提示继续往下拉的文本
         *
         * @param pullDownRefreshText
         */
        public void setPullDownRefreshText(String pullDownRefreshText) {
            mPullDownRefreshText = pullDownRefreshText;
        }
    
        /**
         * 设置满足刷新条件时的文本
         *
         * @param releaseRefreshText
         */
        public void setReleaseRefreshText(String releaseRefreshText) {
            mReleaseRefreshText = releaseRefreshText;
        }
    
        /**
         * 设置正在刷新时的文本
         *
         * @param refreshingText
         */
        public void setRefreshingText(String refreshingText) {
            mRefreshingText = refreshingText;
        }
    
        @Override
        public View getRefreshHeaderView() {
            if (mRefreshHeaderView == null) {
                mRefreshHeaderView = View.inflate(mContext, R.layout.view_refresh_header_normal, null);
                mRefreshHeaderView.setBackgroundColor(Color.TRANSPARENT);
                if (mRefreshViewBackgroundColorRes != -1) {
                    mRefreshHeaderView.setBackgroundResource(mRefreshViewBackgroundColorRes);
                }
                if (mRefreshViewBackgroundDrawableRes != -1) {
                    mRefreshHeaderView.setBackgroundResource(mRefreshViewBackgroundDrawableRes);
                }
                mHeaderStatusTv = (TextView) mRefreshHeaderView.findViewById(R.id.tv_normal_refresh_header_status);
                mHeaderArrowIv = (ImageView) mRefreshHeaderView.findViewById(R.id.iv_normal_refresh_header_arrow);
                mHeaderChrysanthemumIv = (ImageView) mRefreshHeaderView.findViewById(R.id.iv_normal_refresh_header_chrysanthemum);
                mHeaderChrysanthemumAd = (AnimationDrawable) mHeaderChrysanthemumIv.getDrawable();
                mHeaderStatusTv.setText(mPullDownRefreshText);
            }
            return mRefreshHeaderView;
        }
    
        @Override
        public void handleScale(float scale, int moveYDistance) {
        }
    
        @Override
        public void changeToIdle() {
        }
    
        @Override
        public void changeToPullDown() {
            mHeaderStatusTv.setText(mPullDownRefreshText);
            mHeaderChrysanthemumIv.setVisibility(View.INVISIBLE);
            mHeaderChrysanthemumAd.stop();
            mHeaderArrowIv.setVisibility(View.VISIBLE);
            mDownAnim.setDuration(150);
            mHeaderArrowIv.startAnimation(mDownAnim);
        }
    
        @Override
        public void changeToReleaseRefresh() {
            mHeaderStatusTv.setText(mReleaseRefreshText);
            mHeaderChrysanthemumIv.setVisibility(View.INVISIBLE);
            mHeaderChrysanthemumAd.stop();
            mHeaderArrowIv.setVisibility(View.VISIBLE);
            mHeaderArrowIv.startAnimation(mUpAnim);
        }
    
        @Override
        public void changeToRefreshing() {
            mHeaderStatusTv.setText(mRefreshingText);
            // 必须把动画清空才能隐藏成功
            mHeaderArrowIv.clearAnimation();
            mHeaderArrowIv.setVisibility(View.INVISIBLE);
            mHeaderChrysanthemumIv.setVisibility(View.VISIBLE);
            mHeaderChrysanthemumAd.start();
        }
    
        @Override
        public void onEndRefreshing() {
            mHeaderStatusTv.setText(mPullDownRefreshText);
            mHeaderChrysanthemumIv.setVisibility(View.INVISIBLE);
            mHeaderChrysanthemumAd.stop();
            mHeaderArrowIv.setVisibility(View.VISIBLE);
            mDownAnim.setDuration(0);
            mHeaderArrowIv.startAnimation(mDownAnim);
        }
    
    }
    

    BGARefreshLayout.java

    
    /**
     * @author wangtt
     * 15/5/21 22:35
     * 下拉刷新、上拉加载更多、可添加自定义(固定、可滑动)头部控件(例如慕课网app顶部的广告位)
     */
    public class BGARefreshLayout extends LinearLayout {
        private static final String TAG = BGARefreshLayout.class.getSimpleName();
    
        private BGARefreshViewHolder mRefreshViewHolder;
        /**
         * 整个头部控件,下拉刷新控件mRefreshHeaderView和下拉刷新控件下方的自定义组件mCustomHeaderView的父控件
         */
        private LinearLayout mWholeHeaderView;
        /**
         * 下拉刷新控件
         */
        private View mRefreshHeaderView;
        /**
         * 下拉刷新控件下方的自定义控件
         */
        private View mCustomHeaderView;
        /**
         * 下拉刷新控件下方的自定义控件是否可滚动,默认不可滚动
         */
        private boolean mIsCustomHeaderViewScrollable = false;
        /**
         * 下拉刷新控件的高度
         */
        private int mRefreshHeaderViewHeight;
        /**
         * 当前刷新状态
         */
        private RefreshStatus mCurrentRefreshStatus = RefreshStatus.IDLE;
        /**
         * 上拉加载更多控件
         */
        private View mLoadMoreFooterView;
        /**
         * 上拉加载更多控件的高度
         */
        private int mLoadMoreFooterViewHeight;
        /**
         * 下拉刷新和上拉加载更多代理
         */
        private BGARefreshLayoutDelegate mDelegate;
        /**
         * 手指按下时,y轴方向的偏移量
         */
        private int mWholeHeaderDownY = -1;
        /**
         * 整个头部控件最小的paddingTop
         */
        private int mMinWholeHeaderViewPaddingTop;
        /**
         * 整个头部控件最大的paddingTop
         */
        private int mMaxWholeHeaderViewPaddingTop;
    
        /**
         * 是否处于正在加载更多状态
         */
        private boolean mIsLoadingMore = false;
    
        private AbsListView mAbsListView;
        private ScrollView mScrollView;
        private RecyclerView mRecyclerView;
        private View mNormalView;
        private WebView mWebView;
        private BGAStickyNavLayout mStickyNavLayout;
        private View mContentView;
    
        private float mInterceptTouchDownX = -1;
        private float mInterceptTouchDownY = -1;
        /**
         * 按下时整个头部控件的paddingTop
         */
        private int mWholeHeaderViewDownPaddingTop = 0;
        /**
         * 记录开始下拉刷新时的downY
         */
        private int mRefreshDownY = -1;
    
        /**
         * 是否已经设置内容控件滚动监听器
         */
        private boolean mIsInitedContentViewScrollListener = false;
        /**
         * 触发上拉加载更多时是否显示加载更多控件
         */
        private boolean mIsShowLoadingMoreView = true;
    
        /**
         * 下拉刷新是否可用
         */
        private boolean mPullDownRefreshEnable = true;
    
        private Handler mHandler;
    
        private BGARefreshScaleDelegate mRefreshScaleDelegate;
    
        private int mTouchSlop;
    
        public BGARefreshLayout(Context context) {
            this(context, null);
        }
    
        public BGARefreshLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
            setOrientation(LinearLayout.VERTICAL);
            mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
            mHandler = new Handler(Looper.getMainLooper());
            initWholeHeaderView();
        }
    
        /**
         * 初始化整个头部控件
         */
        private void initWholeHeaderView() {
            mWholeHeaderView = new LinearLayout(getContext());
            mWholeHeaderView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            mWholeHeaderView.setOrientation(LinearLayout.VERTICAL);
            addView(mWholeHeaderView);
        }
    
        @Override
        public void onFinishInflate() {
            super.onFinishInflate();
    
            if (getChildCount() != 2) {
                throw new RuntimeException(BGARefreshLayout.class.getSimpleName() + "必须有且只有一个子控件");
            }
    
            mContentView = getChildAt(1);
            if (mContentView instanceof AbsListView) {
                mAbsListView = (AbsListView) mContentView;
            } else if (mContentView instanceof RecyclerView) {
                mRecyclerView = (RecyclerView) mContentView;
            } else if (mContentView instanceof ScrollView) {
                mScrollView = (ScrollView) mContentView;
            } else if (mContentView instanceof WebView) {
                mWebView = (WebView) mContentView;
            } else if (mContentView instanceof BGAStickyNavLayout) {
                mStickyNavLayout = (BGAStickyNavLayout) mContentView;
                mStickyNavLayout.setRefreshLayout(this);
            }else if (mContentView instanceof FrameLayout){
                FrameLayout frameLayout = (FrameLayout) mContentView;
                View childView = frameLayout.getChildAt(0);
                if (childView instanceof RecyclerView){
                    mRecyclerView = (RecyclerView) childView;
                }
            }else {
                mNormalView = mContentView;
                // 设置为可点击,否则在空白区域无法拖动
                mNormalView.setClickable(true);
            }
        }
    
        public void setRefreshViewHolder(BGARefreshViewHolder refreshViewHolder) {
            mRefreshViewHolder = refreshViewHolder;
            mRefreshViewHolder.setRefreshLayout(this);
            initRefreshHeaderView();
            initLoadMoreFooterView();
        }
    
        public void startChangeWholeHeaderViewPaddingTop(int distance) {
            ValueAnimator animator = ValueAnimator.ofInt(mWholeHeaderView.getPaddingTop(), mWholeHeaderView.getPaddingTop() - distance);
            animator.setDuration(mRefreshViewHolder.getTopAnimDuration());
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int paddingTop = (int) animation.getAnimatedValue();
                    mWholeHeaderView.setPadding(0, paddingTop, 0, 0);
                }
            });
            animator.start();
        }
    
        /**
         * 初始化下拉刷新控件
         *
         * @return
         */
        private void initRefreshHeaderView() {
            mRefreshHeaderView = mRefreshViewHolder.getRefreshHeaderView();
            if (mRefreshHeaderView != null) {
                mRefreshHeaderView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
    
                mRefreshHeaderViewHeight = mRefreshViewHolder.getRefreshHeaderViewHeight();
                mMinWholeHeaderViewPaddingTop = -mRefreshHeaderViewHeight;
                mMaxWholeHeaderViewPaddingTop = (int) (mRefreshHeaderViewHeight * mRefreshViewHolder.getSpringDistanceScale());
    
                mWholeHeaderView.setPadding(0, mMinWholeHeaderViewPaddingTop, 0, 0);
                mWholeHeaderView.addView(mRefreshHeaderView, 0);
            }
        }
    
        /**
         * 设置下拉刷新控件下方的自定义控件
         *
         * @param customHeaderView 下拉刷新控件下方的自定义控件
         * @param scrollable       是否可以滚动
         */
        public void setCustomHeaderView(View customHeaderView, boolean scrollable) {
            if (mCustomHeaderView != null && mCustomHeaderView.getParent() != null) {
                ViewGroup parent = (ViewGroup) mCustomHeaderView.getParent();
                parent.removeView(mCustomHeaderView);
            }
            mCustomHeaderView = customHeaderView;
            if (mCustomHeaderView != null) {
                mCustomHeaderView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
                mWholeHeaderView.addView(mCustomHeaderView);
                mIsCustomHeaderViewScrollable = scrollable;
            }
        }
    
        /**
         * 初始化上拉加载更多控件
         *
         * @return
         */
        private void initLoadMoreFooterView() {
            mLoadMoreFooterView = mRefreshViewHolder.getLoadMoreFooterView();
            if (mLoadMoreFooterView != null) {
                // 测量上拉加载更多控件的高度
                mLoadMoreFooterView.measure(0, 0);
                mLoadMoreFooterViewHeight = mLoadMoreFooterView.getMeasuredHeight();
                mLoadMoreFooterView.setVisibility(GONE);
            }
        }
    
        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
    
            // 被添加到窗口后再设置监听器,这样开发者就不必烦恼先初始化RefreshLayout还是先设置自定义滚动监听器
            if (!mIsInitedContentViewScrollListener && mLoadMoreFooterView != null) {
                setRecyclerViewOnScrollListener();
                setAbsListViewOnScrollListener();
    
                addView(mLoadMoreFooterView, getChildCount());
    
                mIsInitedContentViewScrollListener = true;
            }
        }
    
        private void setRecyclerViewOnScrollListener() {
            if (mRecyclerView != null) {
                mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                    @Override
                    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                        if ((newState == RecyclerView.SCROLL_STATE_IDLE || newState == RecyclerView.SCROLL_STATE_SETTLING) && shouldHandleRecyclerViewLoadingMore(mRecyclerView)) {
                            beginLoadingMore();
                        }
                    }
                });
            }
        }
    
        private void setAbsListViewOnScrollListener() {
            if (mAbsListView != null) {
                try {
                    // 通过反射获取开发者自定义的滚动监听器,并将其替换成自己的滚动监听器,触发滚动时也要通知开发者自定义的滚动监听器(非侵入式,不让开发者继承特定的控件)
                    // mAbsListView.getClass().getDeclaredField("mOnScrollListener")获取不到mOnScrollListener,必须通过AbsListView.class.getDeclaredField("mOnScrollListener")获取
                    Field field = AbsListView.class.getDeclaredField("mOnScrollListener");
                    field.setAccessible(true);
                    // 开发者自定义的滚动监听器
                    final AbsListView.OnScrollListener onScrollListener = (AbsListView.OnScrollListener) field.get(mAbsListView);
                    mAbsListView.setOnScrollListener(new AbsListView.OnScrollListener() {
                        @Override
                        public void onScrollStateChanged(AbsListView absListView, int scrollState) {
                            if ((scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) && shouldHandleAbsListViewLoadingMore(mAbsListView)) {
                                beginLoadingMore();
                            }
    
                            if (onScrollListener != null) {
                                onScrollListener.onScrollStateChanged(absListView, scrollState);
                            }
                        }
    
                        @Override
                        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                            if (onScrollListener != null) {
                                onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
                            }
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        public boolean shouldHandleAbsListViewLoadingMore(AbsListView absListView) {
            if (mIsLoadingMore || mCurrentRefreshStatus == RefreshStatus.REFRESHING || mLoadMoreFooterView == null || mDelegate == null || absListView == null || absListView.getAdapter() == null || absListView.getAdapter().getCount() == 0) {
                return false;
            }
    
            return BGARefreshScrollingUtil.isAbsListViewToBottom(absListView);
        }
    
        public boolean shouldHandleRecyclerViewLoadingMore(RecyclerView recyclerView) {
            if (mIsLoadingMore || mCurrentRefreshStatus == RefreshStatus.REFRESHING || mLoadMoreFooterView == null || mDelegate == null || recyclerView.getAdapter() == null || recyclerView.getAdapter().getItemCount() == 0) {
                return false;
            }
            return BGARefreshScrollingUtil.isRecyclerViewToBottom(recyclerView);
        }
    
        /**
         * 是否满足处理刷新的条件
         *
         * @return
         */
        private boolean shouldHandleLoadingMore() {
            if (mIsLoadingMore || mCurrentRefreshStatus == RefreshStatus.REFRESHING || mLoadMoreFooterView == null || mDelegate == null) {
                return false;
            }
    
            // 内容是普通控件,满足
            if (mNormalView != null) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isWebViewToBottom(mWebView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isScrollViewToBottom(mScrollView)) {
                return true;
            }
    
            if (mAbsListView != null) {
                return shouldHandleAbsListViewLoadingMore(mAbsListView);
            }
    
            if (mRecyclerView != null) {
                return shouldHandleRecyclerViewLoadingMore(mRecyclerView);
            }
    
            if (mStickyNavLayout != null) {
                return mStickyNavLayout.shouldHandleLoadingMore();
            }
    
            return false;
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mInterceptTouchDownX = event.getRawX();
                    mInterceptTouchDownY = event.getRawY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (!mIsLoadingMore && (mCurrentRefreshStatus != RefreshStatus.REFRESHING)) {
                        if (mInterceptTouchDownX == -1) {
                            mInterceptTouchDownX = (int) event.getRawX();
                        }
                        if (mInterceptTouchDownY == -1) {
                            mInterceptTouchDownY = (int) event.getRawY();
                        }
    
                        int interceptTouchMoveDistanceY = (int) (event.getRawY() - mInterceptTouchDownY);
                        // 可以没有上拉加载更多,但是必须有下拉刷新,否则就不拦截事件
                        if (Math.abs(event.getRawX() - mInterceptTouchDownX) < Math.abs(interceptTouchMoveDistanceY) && mRefreshHeaderView != null) {
                            if ((interceptTouchMoveDistanceY > mTouchSlop && shouldHandleRefresh()) || (interceptTouchMoveDistanceY < -mTouchSlop && shouldHandleLoadingMore()) || (interceptTouchMoveDistanceY < -mTouchSlop && !isWholeHeaderViewCompleteInvisible()) || (interceptTouchMoveDistanceY > mTouchSlop && shouldInterceptToMoveCustomHeaderViewDown())) {
    
                                // ACTION_DOWN时没有消耗掉事件,子控件会处于按下状态,这里设置ACTION_CANCEL,使子控件取消按下状态
                                event.setAction(MotionEvent.ACTION_CANCEL);
                                super.onInterceptTouchEvent(event);
                                return true;
                            }
                        }
                    }
                    break;
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_UP:
                    // 重置
                    mInterceptTouchDownX = -1;
                    mInterceptTouchDownY = -1;
                    break;
            }
    
            return super.onInterceptTouchEvent(event);
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            if (mIsCustomHeaderViewScrollable && !isWholeHeaderViewCompleteInvisible()) {
                super.dispatchTouchEvent(ev);
                return true;
            }
            return super.dispatchTouchEvent(ev);
        }
    
        /**
         * 是否满足处理刷新的条件
         *
         * @return
         */
        private boolean shouldHandleRefresh() {
            if (!mPullDownRefreshEnable || mIsLoadingMore || mCurrentRefreshStatus == RefreshStatus.REFRESHING || mRefreshHeaderView == null || mDelegate == null) {
                return false;
            }
    
            return isContentViewToTop();
        }
    
        private boolean isContentViewToTop() {
            // 内容是普通控件,满足
            if (mNormalView != null) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isScrollViewOrWebViewToTop(mWebView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isScrollViewOrWebViewToTop(mScrollView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isAbsListViewToTop(mAbsListView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isRecyclerViewToTop(mRecyclerView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isStickyNavLayoutToTop(mStickyNavLayout)) {
                return true;
            }
    
            return false;
        }
    
        private boolean shouldInterceptToMoveCustomHeaderViewDown() {
            return isContentViewToTop() && mCustomHeaderView != null && mIsCustomHeaderViewScrollable && !isCustomHeaderViewCompleteVisible();
        }
    
        private boolean shouldInterceptToMoveCustomHeaderViewUp() {
            return isContentViewToTop() && mCustomHeaderView != null && mIsCustomHeaderViewScrollable && !isWholeHeaderViewCompleteInvisible();
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (null != mRefreshHeaderView) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        mWholeHeaderDownY = (int) event.getY();
                        if (mCustomHeaderView != null) {
                            mWholeHeaderViewDownPaddingTop = mWholeHeaderView.getPaddingTop();
                        }
    
                        if (mCustomHeaderView == null || !mIsCustomHeaderViewScrollable) {
                            mRefreshDownY = (int) event.getY();
                        }
                        if (isWholeHeaderViewCompleteInvisible()) {
                            mRefreshDownY = (int) event.getY();
                            return true;
                        }
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if (handleActionMove(event)) {
                            return true;
                        }
                        break;
                    case MotionEvent.ACTION_CANCEL:
                    case MotionEvent.ACTION_UP:
                        if (handleActionUpOrCancel(event)) {
                            return true;
                        }
                        break;
                    default:
                        break;
                }
            }
            return super.onTouchEvent(event);
        }
    
        /**
         * 自定义头部控件是否已经完全显示
         *
         * @return true表示已经完全显示,false表示没有完全显示
         */
        private boolean isCustomHeaderViewCompleteVisible() {
            if (mCustomHeaderView != null) {
                // 0表示x,1表示y
                int[] location = new int[2];
                getLocationOnScreen(location);
                int mOnScreenY = location[1];
    
                mCustomHeaderView.getLocationOnScreen(location);
                int customHeaderViewOnScreenY = location[1];
                if (mOnScreenY <= customHeaderViewOnScreenY) {
                    return true;
                } else {
                    return false;
                }
    
            }
            return true;
        }
    
        /**
         * 整个头部控件是否已经完全隐藏
         *
         * @return true表示完全隐藏,false表示没有完全隐藏
         */
        private boolean isWholeHeaderViewCompleteInvisible() {
            if (mCustomHeaderView != null && mIsCustomHeaderViewScrollable) {
                // 0表示x,1表示y
                int[] location = new int[2];
                getLocationOnScreen(location);
                int mOnScreenY = location[1];
    
                mWholeHeaderView.getLocationOnScreen(location);
                int wholeHeaderViewOnScreenY = location[1];
                if (wholeHeaderViewOnScreenY + mWholeHeaderView.getMeasuredHeight() <= mOnScreenY) {
                    return true;
                } else {
                    return false;
                }
            }
            return true;
        }
    
        /**
         * 处理手指滑动事件
         *
         * @param event
         * @return true表示自己消耗掉该事件,false表示不消耗该事件
         */
        private boolean handleActionMove(MotionEvent event) {
            if (mCurrentRefreshStatus == RefreshStatus.REFRESHING || mIsLoadingMore) {
                return false;
            }
    
            if ((mCustomHeaderView == null || !mIsCustomHeaderViewScrollable) && mRefreshDownY == -1) {
                mRefreshDownY = (int) event.getY();
            }
            if (mCustomHeaderView != null && mIsCustomHeaderViewScrollable && isCustomHeaderViewCompleteVisible() && mRefreshDownY == -1) {
                mRefreshDownY = (int) event.getY();
            }
    
            int refreshDiffY = (int) event.getY() - mRefreshDownY;
            refreshDiffY = (int) (refreshDiffY / mRefreshViewHolder.getPaddingTopScale());
    
            // 如果是向下拉,并且当前可见的第一个条目的索引等于0,才处理整个头部控件的padding
            if (refreshDiffY > 0 && shouldHandleRefresh() && isCustomHeaderViewCompleteVisible()) {
                int paddingTop = mMinWholeHeaderViewPaddingTop + refreshDiffY;
                if (paddingTop > 0 && mCurrentRefreshStatus != RefreshStatus.RELEASE_REFRESH) {
                    // 下拉刷新控件完全显示,并且当前状态没有处于释放开始刷新状态
                    mCurrentRefreshStatus = RefreshStatus.RELEASE_REFRESH;
                    handleRefreshStatusChanged();
    
                    mRefreshViewHolder.handleScale(1.0f, refreshDiffY);
    
                    if (mRefreshScaleDelegate != null) {
                        mRefreshScaleDelegate.onRefreshScaleChanged(1.0f, refreshDiffY);
                    }
                } else if (paddingTop < 0) {
                    // 下拉刷新控件没有完全显示,并且当前状态没有处于下拉刷新状态
                    if (mCurrentRefreshStatus != RefreshStatus.PULL_DOWN) {
                        boolean isPreRefreshStatusNotIdle = mCurrentRefreshStatus != RefreshStatus.IDLE;
                        mCurrentRefreshStatus = RefreshStatus.PULL_DOWN;
                        if (isPreRefreshStatusNotIdle) {
                            handleRefreshStatusChanged();
                        }
                    }
                    float scale = 1 - paddingTop * 1.0f / mMinWholeHeaderViewPaddingTop;
                    /**
                     * 往下滑
                     * paddingTop    mMinWholeHeaderViewPaddingTop 到 0
                     * scale         0 到 1
                     * 往上滑
                     * paddingTop    0 到 mMinWholeHeaderViewPaddingTop
                     * scale         1 到 0
                     */
                    mRefreshViewHolder.handleScale(scale, refreshDiffY);
    
                    if (mRefreshScaleDelegate != null) {
                        mRefreshScaleDelegate.onRefreshScaleChanged(scale, refreshDiffY);
                    }
                }
                paddingTop = Math.min(paddingTop, mMaxWholeHeaderViewPaddingTop);
                mWholeHeaderView.setPadding(0, paddingTop, 0, 0);
    
                if (mRefreshViewHolder.canChangeToRefreshingStatus()) {
                    mWholeHeaderDownY = -1;
                    mRefreshDownY = -1;
    
                    beginRefreshing();
                }
    
                return true;
            }
    
    
            if (mCustomHeaderView != null && mIsCustomHeaderViewScrollable) {
                if (mWholeHeaderDownY == -1) {
                    mWholeHeaderDownY = (int) event.getY();
    
                    if (mCustomHeaderView != null) {
                        mWholeHeaderViewDownPaddingTop = mWholeHeaderView.getPaddingTop();
                    }
                }
    
                int wholeHeaderDiffY = (int) event.getY() - mWholeHeaderDownY;
                if ((mPullDownRefreshEnable && !isWholeHeaderViewCompleteInvisible()) || (wholeHeaderDiffY > 0 && shouldInterceptToMoveCustomHeaderViewDown()) || (wholeHeaderDiffY < 0 && shouldInterceptToMoveCustomHeaderViewUp())) {
    
                    int paddingTop = mWholeHeaderViewDownPaddingTop + wholeHeaderDiffY;
                    if (paddingTop < mMinWholeHeaderViewPaddingTop - mCustomHeaderView.getMeasuredHeight()) {
                        paddingTop = mMinWholeHeaderViewPaddingTop - mCustomHeaderView.getMeasuredHeight();
                    }
                    mWholeHeaderView.setPadding(0, paddingTop, 0, 0);
    
                    return true;
                }
            }
    
            return false;
        }
    
        /**
         * 处理手指抬起事件
         *
         * @return true表示自己消耗掉该事件,false表示不消耗该事件
         */
        private boolean handleActionUpOrCancel(MotionEvent event) {
            boolean isReturnTrue = false;
            // 如果当前头部刷新控件没有完全隐藏,则需要返回true,自己消耗ACTION_UP事件
            if ((mCustomHeaderView == null || (mCustomHeaderView != null && !mIsCustomHeaderViewScrollable)) && mWholeHeaderView.getPaddingTop() != mMinWholeHeaderViewPaddingTop) {
                isReturnTrue = true;
            }
    
            if (mCurrentRefreshStatus == RefreshStatus.PULL_DOWN || mCurrentRefreshStatus == RefreshStatus.IDLE) {
                // 处于下拉刷新状态,松手时隐藏下拉刷新控件
                if (mCustomHeaderView == null || (mCustomHeaderView != null && mWholeHeaderView.getPaddingTop() < 0 && mWholeHeaderView.getPaddingTop() > mMinWholeHeaderViewPaddingTop)) {
                    hiddenRefreshHeaderView();
                }
                mCurrentRefreshStatus = RefreshStatus.IDLE;
                handleRefreshStatusChanged();
            } else if (mCurrentRefreshStatus == RefreshStatus.RELEASE_REFRESH) {
                // 处于松开进入刷新状态,松手时完全显示下拉刷新控件,进入正在刷新状态
                beginRefreshing();
            }
    
            if (mRefreshDownY == -1) {
                mRefreshDownY = (int) event.getY();
            }
            int diffY = (int) event.getY() - mRefreshDownY;
            if (shouldHandleLoadingMore() && diffY <= 0) {
                // 处理上拉加载更多,需要返回true,自己消耗ACTION_UP事件
                isReturnTrue = true;
                beginLoadingMore();
            }
    
            mWholeHeaderDownY = -1;
            mRefreshDownY = -1;
            return isReturnTrue;
        }
    
        /**
         * 处理下拉刷新控件状态变化
         */
        private void handleRefreshStatusChanged() {
            switch (mCurrentRefreshStatus) {
                case IDLE:
                    mRefreshViewHolder.changeToIdle();
                    break;
                case PULL_DOWN:
                    mRefreshViewHolder.changeToPullDown();
                    break;
                case RELEASE_REFRESH:
                    mRefreshViewHolder.changeToReleaseRefresh();
                    break;
                case REFRESHING:
                    mRefreshViewHolder.changeToRefreshing();
                    break;
                default:
                    break;
            }
        }
    
        /**
         * 切换到正在刷新状态,会调用delegate的onBGARefreshLayoutBeginRefreshing方法
         */
        public void beginRefreshing() {
            if (mCurrentRefreshStatus != RefreshStatus.REFRESHING && mDelegate != null) {
                mCurrentRefreshStatus = RefreshStatus.REFRESHING;
                changeRefreshHeaderViewToZero();
                handleRefreshStatusChanged();
                mDelegate.onBGARefreshLayoutBeginRefreshing(this);
            }
        }
    
        /**
         * 结束下拉刷新
         */
        public void endRefreshing() {
            if (mCurrentRefreshStatus == RefreshStatus.REFRESHING) {
                mCurrentRefreshStatus = RefreshStatus.IDLE;
                hiddenRefreshHeaderView();
                handleRefreshStatusChanged();
                mRefreshViewHolder.onEndRefreshing();
            }
        }
    
        /**
         * 隐藏下拉刷新控件,带动画
         */
        private void hiddenRefreshHeaderView() {
            ValueAnimator animator = ValueAnimator.ofInt(mWholeHeaderView.getPaddingTop(), mMinWholeHeaderViewPaddingTop);
            animator.setDuration(mRefreshViewHolder.getTopAnimDuration());
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int paddingTop = (int) animation.getAnimatedValue();
                    mWholeHeaderView.setPadding(0, paddingTop, 0, 0);
                }
            });
            animator.start();
        }
    
        /**
         * 设置下拉刷新控件的paddingTop到0,带动画
         */
        private void changeRefreshHeaderViewToZero() {
            ValueAnimator animator = ValueAnimator.ofInt(mWholeHeaderView.getPaddingTop(), 0);
            animator.setDuration(mRefreshViewHolder.getTopAnimDuration());
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int paddingTop = (int) animation.getAnimatedValue();
                    mWholeHeaderView.setPadding(0, paddingTop, 0, 0);
                }
            });
            animator.start();
        }
    
        /**
         * 开始上拉加载更多,会触发delegate的onBGARefreshLayoutBeginRefreshing方法
         */
        public void beginLoadingMore() {
            if (!mIsLoadingMore && mLoadMoreFooterView != null && mDelegate != null && mDelegate.onBGARefreshLayoutBeginLoadingMore(this)) {
                mIsLoadingMore = true;
    
                if (mIsShowLoadingMoreView) {
                    showLoadingMoreView();
                }
            }
        }
    
        /**
         * 显示上拉加载更多控件
         */
        private void showLoadingMoreView() {
            mRefreshViewHolder.changeToLoadingMore();
            mLoadMoreFooterView.setVisibility(VISIBLE);
    
            BGARefreshScrollingUtil.scrollToBottom(mScrollView);
            BGARefreshScrollingUtil.scrollToBottom(mRecyclerView);
            BGARefreshScrollingUtil.scrollToBottom(mAbsListView);
            if (mStickyNavLayout != null) {
                mStickyNavLayout.scrollToBottom();
            }
        }
    
        /**
         * 结束上拉加载更多
         */
        public void endLoadingMore() {
            if (mIsLoadingMore) {
                if (mIsShowLoadingMoreView) {
                    // 避免WiFi环境下请求数据太快,加载更多控件一闪而过
                    mHandler.postDelayed(mDelayHiddenLoadingMoreViewTask, 300);
                } else {
                    mIsLoadingMore = false;
                }
            }
        }
    
        private Runnable mDelayHiddenLoadingMoreViewTask = new Runnable() {
            @Override
            public void run() {
                mIsLoadingMore = false;
                mRefreshViewHolder.onEndLoadingMore();
                mLoadMoreFooterView.setVisibility(GONE);
            }
        };
    
        /**
         * 上拉加载更多时是否显示加载更多控件
         *
         * @param isShowLoadingMoreView
         */
        public void setIsShowLoadingMoreView(boolean isShowLoadingMoreView) {
            mIsShowLoadingMoreView = isShowLoadingMoreView;
        }
    
        /**
         * 设置下拉刷新是否可用
         *
         * @param pullDownRefreshEnable
         */
        public void setPullDownRefreshEnable(boolean pullDownRefreshEnable) {
            mPullDownRefreshEnable = pullDownRefreshEnable;
        }
    
        /**
         * 设置下拉刷新上拉加载更多代理
         *
         * @param delegate
         */
        public void setDelegate(BGARefreshLayoutDelegate delegate) {
            mDelegate = delegate;
        }
    
        /**
         * 设置下拉刷新控件可见时,上下拉进度的代理
         *
         * @param refreshScaleDelegate
         */
        public void setRefreshScaleDelegate(BGARefreshScaleDelegate refreshScaleDelegate) {
            mRefreshScaleDelegate = refreshScaleDelegate;
        }
    
        /**
         * 获取当前下拉刷新的状态
         *
         * @return
         */
        public RefreshStatus getCurrentRefreshStatus() {
            return mCurrentRefreshStatus;
        }
    
        /**
         * 是否处于正在加载更多状态
         *
         * @return
         */
        public boolean isLoadingMore() {
            return mIsLoadingMore;
        }
    
        public interface BGARefreshLayoutDelegate {
            /**
             * 开始刷新
             */
            void onBGARefreshLayoutBeginRefreshing(BGARefreshLayout refreshLayout);
    
            /**
             * 开始加载更多。由于监听了ScrollView、RecyclerView、AbsListView滚动到底部的事件,所以这里采用返回boolean来处理是否加载更多。否则使用endLoadingMore方法会失效
             *
             * @param refreshLayout
             * @return 如果要开始加载更多则返回true,否则返回false。(返回false的场景:没有网络、一共只有x页数据并且已经加载了x页数据了)
             */
            boolean onBGARefreshLayoutBeginLoadingMore(BGARefreshLayout refreshLayout);
        }
    
        public interface BGARefreshScaleDelegate {
            /**
             * 下拉刷新控件可见时,处理上下拉进度
             *
             * @param scale         下拉过程0 到 1,回弹过程1 到 0,没有加上弹簧距离移动时的比例
             * @param moveYDistance 整个下拉刷新控件paddingTop变化的值,如果有弹簧距离,会大于整个下拉刷新控件的高度
             */
            void onRefreshScaleChanged(float scale, int moveYDistance);
        }
    
        public enum RefreshStatus {
            IDLE, PULL_DOWN, RELEASE_REFRESH, REFRESHING
        }
    
        public static int dp2px(Context context, int dpValue) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, context.getResources().getDisplayMetrics());
        }
    }
    

    BGARefreshScrollingUtil.java

    
    /**
     * @author wangtingting
     * 15/10/28 上午2:26
     */
    public class BGARefreshScrollingUtil {
    
        private BGARefreshScrollingUtil() {
        }
    
        public static boolean isScrollViewOrWebViewToTop(View view) {
            return view != null && view.getScrollY() == 0;
        }
    
        public static boolean isAbsListViewToTop(AbsListView absListView) {
            if (absListView != null) {
                int firstChildTop = 0;
                if (absListView.getChildCount() > 0) {
                    // 如果AdapterView的子控件数量不为0,获取第一个子控件的top
                    firstChildTop = absListView.getChildAt(0).getTop() - absListView.getPaddingTop();
                }
                if (absListView.getFirstVisiblePosition() == 0 && firstChildTop == 0) {
                    return true;
                }
            }
            return false;
        }
    
        public static boolean isRecyclerViewToTop(RecyclerView recyclerView) {
            if (recyclerView != null) {
                RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
                if (manager == null) {
                    return true;
                }
                if (manager.getItemCount() == 0) {
                    return true;
                }
    
                if (manager instanceof LinearLayoutManager) {
                    LinearLayoutManager layoutManager = (LinearLayoutManager) manager;
    
                    int firstChildTop = 0;
                    if (recyclerView.getChildCount() > 0) {
                        // 处理item高度超过一屏幕时的情况
                        View firstVisibleChild = recyclerView.getChildAt(0);
                        if (firstVisibleChild != null && firstVisibleChild.getMeasuredHeight() >= recyclerView.getMeasuredHeight()) {
                            if (android.os.Build.VERSION.SDK_INT < 14) {
                                return !(ViewCompat.canScrollVertically(recyclerView, -1) || recyclerView.getScrollY() > 0);
                            } else {
                                return !ViewCompat.canScrollVertically(recyclerView, -1);
                            }
                        }
    
                        // 如果RecyclerView的子控件数量不为0,获取第一个子控件的top
    
                        // 解决item的topMargin不为0时不能触发下拉刷新
                        View firstChild = recyclerView.getChildAt(0);
                        RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) firstChild.getLayoutParams();
                        firstChildTop = firstChild.getTop() - layoutParams.topMargin - getRecyclerViewItemTopInset(layoutParams) - recyclerView.getPaddingTop();
                    }
    
                    if (layoutManager.findFirstCompletelyVisibleItemPosition() < 1 && firstChildTop == 0) {
                        return true;
                    }
                } else if (manager instanceof StaggeredGridLayoutManager) {
                    StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) manager;
    
                    int[] out = layoutManager.findFirstCompletelyVisibleItemPositions(null);
                    if (out[0] < 1) {
                        return true;
                    }
                }
            }
            return false;
        }
    
        /**
         * 通过反射获取RecyclerView的item的topInset
         *
         * @param layoutParams
         * @return
         */
        private static int getRecyclerViewItemTopInset(RecyclerView.LayoutParams layoutParams) {
            try {
                Field field = RecyclerView.LayoutParams.class.getDeclaredField("mDecorInsets");
                field.setAccessible(true);
                // 开发者自定义的滚动监听器
                Rect decorInsets = (Rect) field.get(layoutParams);
                return decorInsets.top;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return 0;
        }
    
        public static boolean isStickyNavLayoutToTop(BGAStickyNavLayout stickyNavLayout) {
            return isScrollViewOrWebViewToTop(stickyNavLayout) && stickyNavLayout.isContentViewToTop();
        }
    
    
        public static boolean isWebViewToBottom(WebView webView) {
            return webView != null && webView.getContentHeight() * webView.getScale() == (webView.getScrollY() + webView.getMeasuredHeight());
        }
    
        public static boolean isScrollViewToBottom(ScrollView scrollView) {
            if (scrollView != null) {
                int scrollContentHeight = scrollView.getScrollY() + scrollView.getMeasuredHeight() - scrollView.getPaddingTop() - scrollView.getPaddingBottom();
                int realContentHeight = scrollView.getChildAt(0).getMeasuredHeight();
                if (scrollContentHeight == realContentHeight) {
                    return true;
                }
            }
            return false;
        }
    
        public static boolean isAbsListViewToBottom(AbsListView absListView) {
            if (absListView != null && absListView.getAdapter() != null && absListView.getChildCount() > 0 && absListView.getLastVisiblePosition() == absListView.getAdapter().getCount() - 1) {
                View lastChild = absListView.getChildAt(absListView.getChildCount() - 1);
    
                BGAStickyNavLayout stickyNavLayout = getStickyNavLayout(absListView);
                if (stickyNavLayout != null) {
                    // 处理BGAStickyNavLayout中lastChild.getBottom() <= absListView.getMeasuredHeight()失效问题
    
                    // 0表示x,1表示y
                    int[] location = new int[2];
                    lastChild.getLocationOnScreen(location);
                    int lastChildBottomOnScreen = location[1] + lastChild.getMeasuredHeight();
                    stickyNavLayout.getLocationOnScreen(location);
                    int stickyNavLayoutBottomOnScreen = location[1] + stickyNavLayout.getMeasuredHeight();
                    return lastChildBottomOnScreen + absListView.getPaddingBottom() <= stickyNavLayoutBottomOnScreen;
                } else {
                    return lastChild.getBottom() <= absListView.getMeasuredHeight();
                }
            }
            return false;
        }
    
        public static boolean isRecyclerViewToBottom(RecyclerView recyclerView) {
            if (recyclerView != null) {
                RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
                if (manager == null || manager.getItemCount() == 0) {
                    return false;
                }
    
                if (manager instanceof LinearLayoutManager) {
                    // 处理item高度超过一屏幕时的情况
                    View lastVisibleChild = recyclerView.getChildAt(recyclerView.getChildCount() - 1);
                    if (lastVisibleChild != null && lastVisibleChild.getMeasuredHeight() >= recyclerView.getMeasuredHeight()) {
                        if (android.os.Build.VERSION.SDK_INT < 14) {
                            return !(ViewCompat.canScrollVertically(recyclerView, 1) || recyclerView.getScrollY() < 0);
                        } else {
                            return !ViewCompat.canScrollVertically(recyclerView, 1);
                        }
                    }
    
                    LinearLayoutManager layoutManager = (LinearLayoutManager) manager;
                    if (layoutManager.findLastCompletelyVisibleItemPosition() == layoutManager.getItemCount() - 1) {
                        BGAStickyNavLayout stickyNavLayout = getStickyNavLayout(recyclerView);
                        if (stickyNavLayout != null) {
                            // 处理BGAStickyNavLayout中findLastCompletelyVisibleItemPosition失效问题
                            View lastCompletelyVisibleChild = layoutManager.getChildAt(layoutManager.findLastCompletelyVisibleItemPosition());
                            if (lastCompletelyVisibleChild == null) {
                                return true;
                            } else {
                                // 0表示x,1表示y
                                int[] location = new int[2];
                                lastCompletelyVisibleChild.getLocationOnScreen(location);
                                int lastChildBottomOnScreen = location[1] + lastCompletelyVisibleChild.getMeasuredHeight();
                                stickyNavLayout.getLocationOnScreen(location);
                                int stickyNavLayoutBottomOnScreen = location[1] + stickyNavLayout.getMeasuredHeight();
                                return lastChildBottomOnScreen <= stickyNavLayoutBottomOnScreen;
                            }
                        } else {
                            return true;
                        }
                    }
                } else if (manager instanceof StaggeredGridLayoutManager) {
                    StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) manager;
    
                    int[] out = layoutManager.findLastCompletelyVisibleItemPositions(null);
                    int lastPosition = layoutManager.getItemCount() - 1;
                    for (int position : out) {
                        if (position == lastPosition) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
    
    
        public static void scrollToBottom(final ScrollView scrollView) {
            if (scrollView != null) {
                scrollView.post(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.fullScroll(ScrollView.FOCUS_DOWN);
                    }
                });
            }
        }
    
        public static void scrollToBottom(final AbsListView absListView) {
            if (absListView != null) {
                if (absListView.getAdapter() != null && absListView.getAdapter().getCount() > 0) {
                    absListView.post(new Runnable() {
                        @Override
                        public void run() {
                            absListView.setSelection(absListView.getAdapter().getCount() - 1);
                        }
                    });
                }
            }
        }
    
        public static void scrollToBottom(final RecyclerView recyclerView) {
            if (recyclerView != null) {
                if (recyclerView.getAdapter() != null && recyclerView.getAdapter().getItemCount() > 0) {
                    recyclerView.post(new Runnable() {
                        @Override
                        public void run() {
                            recyclerView.smoothScrollToPosition(recyclerView.getAdapter().getItemCount() - 1);
                        }
                    });
                }
            }
        }
    
        public static BGAStickyNavLayout getStickyNavLayout(View view) {
            ViewParent viewParent = view.getParent();
            while (viewParent != null) {
                if (viewParent instanceof BGAStickyNavLayout) {
                    return (BGAStickyNavLayout) viewParent;
                }
                viewParent = viewParent.getParent();
            }
            return null;
        }
    
        public static int getScreenHeight(Context context) {
            WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics dm = new DisplayMetrics();
            windowManager.getDefaultDisplay().getMetrics(dm);
            return dm.heightPixels;
        }
    }
    

    BGARefreshViewHolder.java

    
    
    /**
     * @author wangtt
     * 15/5/21 12:56
     * 描述:继承该抽象类实现响应的抽象方法,做出各种下拉刷新效果。参考BGANormalRefreshViewHolder、BGAStickinessRefreshViewHolder、BGAMoocStyleRefreshViewHolder、BGAMeiTuanRefreshViewHolder
     */
    public abstract class BGARefreshViewHolder {
        /**
         * 手指移动距离与下拉刷新控件paddingTop移动距离的比值
         */
        private static final float PULL_DISTANCE_SCALE = 1.8f;
        /**
         * 手指移动距离与下拉刷新控件paddingTop移动距离的比值,默认1.8f
         */
        private float mPullDistanceScale = PULL_DISTANCE_SCALE;
        /**
         * 下拉刷新控件paddingTop的弹簧距离与下拉刷新控件高度的比值
         */
        private static final float SPRING_DISTANCE_SCALE = 0.4f;
        /**
         * 下拉刷新控件paddingTop的弹簧距离与下拉刷新控件高度的比值,默认0.4f
         */
        private float mSpringDistanceScale = SPRING_DISTANCE_SCALE;
    
        protected Context mContext;
        /**
         * 下拉刷新上拉加载更多控件
         */
        protected BGARefreshLayout mRefreshLayout;
        /**
         * 下拉刷新控件
         */
        protected View mRefreshHeaderView;
        /**
         * 上拉加载更多控件
         */
        protected View mLoadMoreFooterView;
        /**
         * 底部加载更多提示控件
         */
        protected TextView mFooterStatusTv;
        /**
         * 底部加载更多菊花控件
         */
        protected ImageView mFooterChrysanthemumIv;
        /**
         * 底部加载更多菊花drawable
         */
        protected AnimationDrawable mFooterChrysanthemumAd;
        /**
         * 正在加载更多时的文本
         */
        protected String mLodingMoreText = "加载中...";
        /**
         * 是否开启加载更多功能
         */
        private boolean mIsLoadingMoreEnabled = true;
        /**
         * 整个加载更多控件的背景颜色资源id
         */
        private int mLoadMoreBackgroundColorRes = -1;
        /**
         * 整个加载更多控件的背景drawable资源id
         */
        private int mLoadMoreBackgroundDrawableRes = -1;
        /**
         * 下拉刷新控件的背景颜色资源id
         */
        protected int mRefreshViewBackgroundColorRes = -1;
        /**
         * 下拉刷新控件的背景drawable资源id
         */
        protected int mRefreshViewBackgroundDrawableRes = -1;
        /**
         * 头部控件移动动画时常
         */
        private int mTopAnimDuration = 500;
    
        /**
         * @param context
         * @param isLoadingMoreEnabled 上拉加载更多是否可用
         */
        public BGARefreshViewHolder(Context context, boolean isLoadingMoreEnabled) {
            mContext = context;
            mIsLoadingMoreEnabled = isLoadingMoreEnabled;
        }
    
        /**
         * 设置正在加载更多时的文本
         *
         * @param loadingMoreText
         */
        public void setLoadingMoreText(String loadingMoreText) {
            mLodingMoreText = loadingMoreText;
        }
    
        /**
         * 设置整个加载更多控件的背景颜色资源id
         *
         * @param loadMoreBackgroundColorRes
         */
        public void setLoadMoreBackgroundColorRes(@ColorRes int loadMoreBackgroundColorRes) {
            mLoadMoreBackgroundColorRes = loadMoreBackgroundColorRes;
        }
    
        /**
         * 设置整个加载更多控件的背景drawable资源id
         *
         * @param loadMoreBackgroundDrawableRes
         */
        public void setLoadMoreBackgroundDrawableRes(@DrawableRes int loadMoreBackgroundDrawableRes) {
            mLoadMoreBackgroundDrawableRes = loadMoreBackgroundDrawableRes;
        }
    
        /**
         * 设置下拉刷新控件的背景颜色资源id
         *
         * @param refreshViewBackgroundColorRes
         */
        public void setRefreshViewBackgroundColorRes(@ColorRes int refreshViewBackgroundColorRes) {
            mRefreshViewBackgroundColorRes = refreshViewBackgroundColorRes;
        }
    
        /**
         * 设置下拉刷新控件的背景drawable资源id
         *
         * @param refreshViewBackgroundDrawableRes
         */
        public void setRefreshViewBackgroundDrawableRes(@DrawableRes int refreshViewBackgroundDrawableRes) {
            mRefreshViewBackgroundDrawableRes = refreshViewBackgroundDrawableRes;
        }
    
        /**
         * 获取顶部未满足下拉刷新条件时回弹到初始状态、满足刷新条件时回弹到正在刷新状态、刷新完毕后回弹到初始状态的动画时间,默认为500毫秒
         *
         * @return
         */
        public int getTopAnimDuration() {
            return mTopAnimDuration;
        }
    
        /**
         * 设置顶部未满足下拉刷新条件时回弹到初始状态、满足刷新条件时回弹到正在刷新状态、刷新完毕后回弹到初始状态的动画时间,默认为300毫秒
         *
         * @param topAnimDuration
         */
        public void setTopAnimDuration(int topAnimDuration) {
            mTopAnimDuration = topAnimDuration;
        }
    
        /**
         * 获取上拉加载更多控件,如果不喜欢这种上拉刷新风格可重写该方法实现自定义LoadMoreFooterView
         *
         * @return
         */
        public View getLoadMoreFooterView() {
            if (!mIsLoadingMoreEnabled) {
                return null;
            }
            if (mLoadMoreFooterView == null) {
                mLoadMoreFooterView = View.inflate(mContext, R.layout.view_normal_refresh_footer, null);
                mLoadMoreFooterView.setBackgroundColor(Color.TRANSPARENT);
                if (mLoadMoreBackgroundColorRes != -1) {
                    mLoadMoreFooterView.setBackgroundResource(mLoadMoreBackgroundColorRes);
                }
                if (mLoadMoreBackgroundDrawableRes != -1) {
                    mLoadMoreFooterView.setBackgroundResource(mLoadMoreBackgroundDrawableRes);
                }
                mFooterStatusTv = (TextView) mLoadMoreFooterView.findViewById(R.id.tv_normal_refresh_footer_status);
                mFooterChrysanthemumIv = (ImageView) mLoadMoreFooterView.findViewById(R.id.iv_normal_refresh_footer_chrysanthemum);
                mFooterChrysanthemumAd = (AnimationDrawable) mFooterChrysanthemumIv.getDrawable();
                mFooterStatusTv.setText(mLodingMoreText);
            }
            return mLoadMoreFooterView;
        }
    
        /**
         * 获取头部下拉刷新控件
         *
         * @return
         */
        public abstract View getRefreshHeaderView();
    
        /**
         * 下拉刷新控件可见时,处理上下拉进度
         *
         * @param scale         下拉过程0 到 1,回弹过程1 到 0,没有加上弹簧距离移动时的比例
         * @param moveYDistance 整个下拉刷新控件paddingTop变化的值,如果有弹簧距离,会大于整个下拉刷新控件的高度
         */
        public abstract void handleScale(float scale, int moveYDistance);
    
        /**
         * 进入到未处理下拉刷新状态
         */
        public abstract void changeToIdle();
    
        /**
         * 进入下拉状态
         */
        public abstract void changeToPullDown();
    
        /**
         * 进入释放刷新状态
         */
        public abstract void changeToReleaseRefresh();
    
        /**
         * 进入正在刷新状态
         */
        public abstract void changeToRefreshing();
    
        /**
         * 结束下拉刷新
         */
        public abstract void onEndRefreshing();
    
        /**
         * 手指移动距离与下拉刷新控件paddingTop移动距离的比值
         *
         * @return
         */
        public float getPaddingTopScale() {
            return mPullDistanceScale;
        }
    
        /**
         * 设置手指移动距离与下拉刷新控件paddingTop移动距离的比值
         *
         * @param pullDistanceScale
         */
        public void setPullDistanceScale(float pullDistanceScale) {
            mPullDistanceScale = pullDistanceScale;
        }
    
        /**
         * 下拉刷新控件paddingTop的弹簧距离与下拉刷新控件高度的比值
         *
         * @return
         */
        public float getSpringDistanceScale() {
            return mSpringDistanceScale;
        }
    
        /**
         * 设置下拉刷新控件paddingTop的弹簧距离与下拉刷新控件高度的比值,不能小于0,如果刷新控件比较高,建议将该值设置小一些
         *
         * @param springDistanceScale
         */
        public void setSpringDistanceScale(float springDistanceScale) {
            if (springDistanceScale < 0) {
                throw new RuntimeException("下拉刷新控件paddingTop的弹簧距离与下拉刷新控件高度的比值springDistanceScale不能小于0");
            }
            mSpringDistanceScale = springDistanceScale;
        }
    
        /**
         * 是处于能够进入刷新状态
         *
         * @return
         */
        public boolean canChangeToRefreshingStatus() {
            return false;
        }
    
        /**
         * 进入加载更多状态
         */
        public void changeToLoadingMore() {
            if (mIsLoadingMoreEnabled && mFooterChrysanthemumAd != null) {
                mFooterChrysanthemumAd.start();
            }
        }
    
        /**
         * 结束上拉加载更多
         */
        public void onEndLoadingMore() {
            if (mIsLoadingMoreEnabled && mFooterChrysanthemumAd != null) {
                mFooterChrysanthemumAd.stop();
            }
        }
    
        /**
         * 获取下拉刷新控件的高度,如果初始化时的高度和最后展开的最大高度不一致,需重写该方法返回最大高度
         *
         * @return
         */
        public int getRefreshHeaderViewHeight() {
            if (mRefreshHeaderView != null) {
                // 测量下拉刷新控件的高度
                mRefreshHeaderView.measure(0, 0);
                return mRefreshHeaderView.getMeasuredHeight();
            }
            return 0;
        }
    
        /**
         * 改变整个下拉刷新头部控件移动一定的距离(带动画),自定义刷新控件进入刷新状态前后的高度有变化时可以使用该方法(参考BGAStickinessRefreshView)
         *
         * @param distance
         */
        public void startChangeWholeHeaderViewPaddingTop(int distance) {
            mRefreshLayout.startChangeWholeHeaderViewPaddingTop(distance);
        }
    
        /**
         * 设置下拉刷新上拉加载更多控件,该方法是设置BGARefreshViewHolder给BGARefreshLayout时由BGARefreshLayout调用
         *
         * @param refreshLayout
         */
        public void setRefreshLayout(BGARefreshLayout refreshLayout) {
            mRefreshLayout = refreshLayout;
        }
    
    }
    

    BGAStickyNavLayout.java

    
    
    /**
     * @author wangtt
     */
    public class BGAStickyNavLayout extends LinearLayout {
        private View mHeaderView;
        private View mNavView;
        private View mContentView;
    
        private View mDirectNormalView;
        private RecyclerView mDirectRecyclerView;
        private AbsListView mDirectAbsListView;
        private ScrollView mDirectScrollView;
        private WebView mDirectWebView;
        private ViewPager mDirectViewPager;
    
        private View mNestedContentView;
        private View mNestedNormalView;
        private RecyclerView mNestedRecyclerView;
        private AbsListView mNestedAbsListView;
        private ScrollView mNestedScrollView;
        private WebView mNestedWebView;
    
        private OverScroller mOverScroller;
        private VelocityTracker mVelocityTracker;
        private int mTouchSlop;
        private int mMaximumVelocity;
        private int mMinimumVelocity;
    
        private boolean mIsInControl = true;
    
        private float mLastDispatchY;
        private float mLastTouchY;
    
        public BGARefreshLayout mRefreshLayout;
    
        public BGAStickyNavLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        private void init(Context context) {
            setOrientation(VERTICAL);
    
            mOverScroller = new OverScroller(context);
            final ViewConfiguration configuration = ViewConfiguration.get(context);
            mTouchSlop = configuration.getScaledTouchSlop();
            mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
            mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
        }
    
        @Override
        public void setOrientation(int orientation) {
            if (VERTICAL == orientation) {
                super.setOrientation(VERTICAL);
            }
        }
    
        @Override
        public void onFinishInflate() {
            super.onFinishInflate();
    
            if (getChildCount() != 3) {
                throw new IllegalStateException(BGAStickyNavLayout.class.getSimpleName() + "必须有且只有三个子控件");
            }
    
            mHeaderView = getChildAt(0);
            mNavView = getChildAt(1);
            mContentView = getChildAt(2);
    
            if (mContentView instanceof AbsListView) {
                mDirectAbsListView = (AbsListView) mContentView;
                mDirectAbsListView.setOnScrollListener(mLvOnScrollListener);
            } else if (mContentView instanceof RecyclerView) {
                mDirectRecyclerView = (RecyclerView) mContentView;
                mDirectRecyclerView.addOnScrollListener(mRvOnScrollListener);
            } else if (mContentView instanceof ScrollView) {
                mDirectScrollView = (ScrollView) mContentView;
            } else if (mContentView instanceof WebView) {
                mDirectWebView = (WebView) mContentView;
            } else if (mContentView instanceof ViewPager) {
                mDirectViewPager = (ViewPager) mContentView;
                mDirectViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                    @Override
                    public void onPageSelected(int position) {
                        regetNestedContentView();
                    }
                });
            } else {
                mDirectNormalView = mContentView;
            }
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            measureChild(mContentView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) - getNavViewHeight(), MeasureSpec.EXACTLY));
        }
    
        @Override
        public void computeScroll() {
            if (mOverScroller.computeScrollOffset()) {
                scrollTo(0, mOverScroller.getCurrY());
                invalidate();
            }
        }
    
        public void fling(int velocityY) {
            mOverScroller.fling(0, getScrollY(), 0, velocityY, 0, 0, 0, getHeaderViewHeight());
            invalidate();
        }
    
        @Override
        public void scrollTo(int x, int y) {
            if (y < 0) {
                y = 0;
            }
    
            int headerViewHeight = getHeaderViewHeight();
            if (y > headerViewHeight) {
                y = headerViewHeight;
            }
    
            if (y != getScrollY()) {
                super.scrollTo(x, y);
            }
        }
    
        /**
         * 获取头部视图高度,包括topMargin和bottomMargin
         *
         * @return
         */
        private int getHeaderViewHeight() {
            MarginLayoutParams layoutParams = (MarginLayoutParams) mHeaderView.getLayoutParams();
            return mHeaderView.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
        }
    
        /**
         * 获取导航视图的高度,包括topMargin和bottomMargin
         *
         * @return
         */
        private int getNavViewHeight() {
            MarginLayoutParams layoutParams = (MarginLayoutParams) mNavView.getLayoutParams();
            return mNavView.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
        }
    
        /**
         * 头部视图是否已经完全隐藏
         *
         * @return
         */
        private boolean isHeaderViewCompleteInvisible() {
            // 0表示x,1表示y
            int[] location = new int[2];
            getLocationOnScreen(location);
            int contentOnScreenTopY = location[1] + getPaddingTop();
    
            mNavView.getLocationOnScreen(location);
            MarginLayoutParams params = (MarginLayoutParams) mNavView.getLayoutParams();
            int navViewTopOnScreenY = location[1] - params.topMargin;
    
            if (navViewTopOnScreenY == contentOnScreenTopY) {
                return true;
            } else {
                return false;
            }
        }
    
        private void initVelocityTrackerIfNotExists() {
            if (mVelocityTracker == null) {
                mVelocityTracker = VelocityTracker.obtain();
            }
        }
    
        private void recycleVelocityTracker() {
            if (mVelocityTracker != null) {
                mVelocityTracker.recycle();
                mVelocityTracker = null;
            }
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            float currentTouchY = ev.getY();
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mLastDispatchY = currentTouchY;
                    break;
                case MotionEvent.ACTION_MOVE:
                    float differentY = currentTouchY - mLastDispatchY;
                    mLastDispatchY = currentTouchY;
                    if (isContentViewToTop() && isHeaderViewCompleteInvisible()) {
                        if (differentY >= 0 && !mIsInControl) {
                            mIsInControl = true;
    
                            return resetDispatchTouchEvent(ev);
                        }
    
                        if (differentY <= 0 && mIsInControl) {
                            mIsInControl = false;
    
                            return resetDispatchTouchEvent(ev);
                        }
                    }
                    break;
            }
            return super.dispatchTouchEvent(ev);
        }
    
        private boolean resetDispatchTouchEvent(MotionEvent ev) {
            MotionEvent newEvent = MotionEvent.obtain(ev);
    
            ev.setAction(MotionEvent.ACTION_CANCEL);
            dispatchTouchEvent(ev);
    
            newEvent.setAction(MotionEvent.ACTION_DOWN);
            return dispatchTouchEvent(newEvent);
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            float currentTouchY = ev.getY();
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mLastTouchY = currentTouchY;
                    break;
                case MotionEvent.ACTION_MOVE:
                    float differentY = currentTouchY - mLastTouchY;
                    if (Math.abs(differentY) > mTouchSlop) {
                        if (!isHeaderViewCompleteInvisible() || (isContentViewToTop() && isHeaderViewCompleteInvisible() && mIsInControl)) {
                            mLastTouchY = currentTouchY;
                            return true;
                        }
                    }
                    break;
            }
            return super.onInterceptTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            initVelocityTrackerIfNotExists();
            mVelocityTracker.addMovement(event);
    
            float currentTouchY = event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (!mOverScroller.isFinished()) {
                        mOverScroller.abortAnimation();
                    }
    
                    mLastTouchY = currentTouchY;
                    break;
                case MotionEvent.ACTION_MOVE:
                    float differentY = currentTouchY - mLastTouchY;
                    mLastTouchY = currentTouchY;
                    if (Math.abs(differentY) > 0) {
                        scrollBy(0, (int) -differentY);
                    }
                    break;
                case MotionEvent.ACTION_CANCEL:
                    recycleVelocityTracker();
                    if (!mOverScroller.isFinished()) {
                        mOverScroller.abortAnimation();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                    int initialVelocity = (int) mVelocityTracker.getYVelocity();
                    if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
                        fling(-initialVelocity);
                    }
                    recycleVelocityTracker();
                    break;
            }
            return true;
        }
    
        public boolean isContentViewToTop() {
            if (mDirectNormalView != null) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isScrollViewOrWebViewToTop(mDirectWebView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isScrollViewOrWebViewToTop(mDirectScrollView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isAbsListViewToTop(mDirectAbsListView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isRecyclerViewToTop(mDirectRecyclerView)) {
                return true;
            }
    
            if (mDirectViewPager != null) {
                return isViewPagerContentViewToTop();
            }
    
            return false;
        }
    
        private boolean isViewPagerContentViewToTop() {
            if (mNestedContentView == null) {
                regetNestedContentView();
            }
    
            if (mDirectNormalView != null) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isScrollViewOrWebViewToTop(mNestedWebView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isScrollViewOrWebViewToTop(mNestedScrollView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isAbsListViewToTop(mNestedAbsListView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isRecyclerViewToTop(mNestedRecyclerView)) {
                return true;
            }
    
            return false;
        }
    
        /**
         * 重新获取嵌套的内容视图
         */
        private void regetNestedContentView() {
            int currentItem = mDirectViewPager.getCurrentItem();
            PagerAdapter adapter = mDirectViewPager.getAdapter();
            if (adapter instanceof FragmentPagerAdapter || adapter instanceof FragmentStatePagerAdapter) {
                Fragment item = (Fragment) adapter.instantiateItem(mDirectViewPager, currentItem);
                mNestedContentView = item.getView();
    
                // 清空之前的
                mNestedNormalView = null;
                mNestedAbsListView = null;
                mNestedRecyclerView = null;
                mNestedScrollView = null;
                mNestedWebView = null;
    
                if (mNestedContentView instanceof AbsListView) {
                    mNestedAbsListView = (AbsListView) mNestedContentView;
                    mNestedAbsListView.setOnScrollListener(mLvOnScrollListener);
    
                    if (!isHeaderViewCompleteInvisible()) {
                        mNestedAbsListView.setSelection(0);
                    }
                } else if (mNestedContentView instanceof RecyclerView) {
                    mNestedRecyclerView = (RecyclerView) mNestedContentView;
                    mNestedRecyclerView.removeOnScrollListener(mRvOnScrollListener);
                    mNestedRecyclerView.addOnScrollListener(mRvOnScrollListener);
    
                    if (!isHeaderViewCompleteInvisible()) {
                        mNestedRecyclerView.scrollToPosition(0);
                    }
                } else if (mNestedContentView instanceof ScrollView) {
                    mNestedScrollView = (ScrollView) mNestedContentView;
    
                    if (!isHeaderViewCompleteInvisible()) {
                        mNestedScrollView.scrollTo(mNestedScrollView.getScrollX(), 0);
                    }
                } else if (mNestedContentView instanceof WebView) {
                    mNestedWebView = (WebView) mNestedContentView;
    
                    if (!isHeaderViewCompleteInvisible()) {
                        mNestedWebView.scrollTo(mNestedWebView.getScrollX(), 0);
                    }
                } else {
                    mNestedNormalView = mNestedContentView;
                }
            } else {
                throw new IllegalStateException(BGAStickyNavLayout.class.getSimpleName() + "的第三个子控件为ViewPager时,其adapter必须是FragmentPagerAdapter或者FragmentStatePagerAdapter");
            }
        }
    
        public void setRefreshLayout(BGARefreshLayout refreshLayout) {
            mRefreshLayout = refreshLayout;
        }
    
        private RecyclerView.OnScrollListener mRvOnScrollListener = new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                if ((newState == RecyclerView.SCROLL_STATE_IDLE || newState == RecyclerView.SCROLL_STATE_SETTLING) && mRefreshLayout != null && mRefreshLayout.shouldHandleRecyclerViewLoadingMore(recyclerView)) {
                    mRefreshLayout.beginLoadingMore();
                }
            }
        };
    
        private AbsListView.OnScrollListener mLvOnScrollListener = new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView absListView, int scrollState) {
                if ((scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) && mRefreshLayout != null && mRefreshLayout.shouldHandleAbsListViewLoadingMore(absListView)) {
                    mRefreshLayout.beginLoadingMore();
                }
            }
    
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            }
        };
    
        public boolean shouldHandleLoadingMore() {
            if (mRefreshLayout == null) {
                return false;
            }
    
            if (mDirectNormalView != null) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isWebViewToBottom(mDirectWebView)) {
                return true;
            }
    
            if (BGARefreshScrollingUtil.isScrollViewToBottom(mDirectScrollView)) {
                return true;
            }
    
            if (mDirectAbsListView != null) {
                return mRefreshLayout.shouldHandleAbsListViewLoadingMore(mDirectAbsListView);
            }
    
            if (mDirectRecyclerView != null) {
                return mRefreshLayout.shouldHandleRecyclerViewLoadingMore(mDirectRecyclerView);
            }
    
            if (mDirectViewPager != null) {
                if (mNestedContentView == null) {
                    regetNestedContentView();
                }
    
                if (mNestedNormalView != null) {
                    return true;
                }
    
                if (BGARefreshScrollingUtil.isWebViewToBottom(mNestedWebView)) {
                    return true;
                }
    
                if (BGARefreshScrollingUtil.isScrollViewToBottom(mNestedScrollView)) {
                    return true;
                }
    
                if (mNestedAbsListView != null) {
                    return mRefreshLayout.shouldHandleAbsListViewLoadingMore(mNestedAbsListView);
                }
    
                if (mNestedRecyclerView != null) {
                    return mRefreshLayout.shouldHandleRecyclerViewLoadingMore(mNestedRecyclerView);
                }
            }
    
            return false;
        }
    
        public void scrollToBottom() {
            BGARefreshScrollingUtil.scrollToBottom(mDirectScrollView);
            BGARefreshScrollingUtil.scrollToBottom(mDirectRecyclerView);
            BGARefreshScrollingUtil.scrollToBottom(mDirectAbsListView);
    
            if (mDirectViewPager != null) {
                if (mNestedContentView == null) {
                    regetNestedContentView();
                }
                BGARefreshScrollingUtil.scrollToBottom(mNestedScrollView);
                BGARefreshScrollingUtil.scrollToBottom(mNestedRecyclerView);
                BGARefreshScrollingUtil.scrollToBottom(mNestedAbsListView);
            }
        }
    }
    

    DividerDecoration.java

    public class DividerDecoration extends RecyclerView.ItemDecoration {
    
        private int mOrientation;
        private int mDividerSize;
        private Paint mPaint;
        private Drawable mDividerDrawable;
        private int mMarginLeft;
        private int mMarginRight;
    
        /**
         * 颜色分割线
         *
         * @param context     上下文
         * @param orientation 方向
         * @param color       分割线颜色
         * @param dividerSize 分割线大小
         */
        public DividerDecoration(Context context, int orientation, int color, int dividerSize, int marginLeft, int marginRight) {
            if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
                throw new IllegalArgumentException("Orientation is invalidate");
            }
            if (dividerSize <= 0) {
                throw new IllegalArgumentException("DividerSize must be greated than 0");
            }
    
            mOrientation = orientation;
            mDividerSize = dividerSize;
            mMarginLeft = marginLeft;
            mMarginRight = marginRight;
    
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//设置为抗锯齿
            mPaint.setColor(color);//设置画笔颜色
            mPaint.setStyle(Paint.Style.FILL);//设置为填充
        }
    
        /**
         * 图片分割线
         *
         * @param context         上下文
         * @param orientation     方向
         * @param dividerDrawable 分割线图片
         * @param dividerSize     分割线大小
         */
        public DividerDecoration(Context context, int orientation, Drawable dividerDrawable, int dividerSize, int marginLeft, int marginRight) {
            if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
                throw new IllegalArgumentException("Orientation is invalidate");
            }
    
            mOrientation = orientation;
            mDividerDrawable = dividerDrawable;
            mMarginLeft = marginLeft;
            mMarginRight = marginRight;
    
            if (dividerSize > 0) {
                mDividerSize = dividerSize;
            } else {
                //如果传入的dividerSize不大于0,则使用图片的宽或高
                if (mOrientation == LinearLayoutManager.VERTICAL) {
                    //如果是垂直方向,使用图片的高度
                    mDividerSize = mDividerDrawable.getIntrinsicHeight();
                } else {
                    mDividerSize = mDividerDrawable.getIntrinsicWidth();
                }
            }
            Log.i("", "mDividerSize: " + mDividerSize);
        }
    
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            if (mOrientation == LinearLayoutManager.VERTICAL) {
                drawVertical(c, parent);
            } else {
                drawHorizontal(c, parent);
            }
        }
    
        /**
         * 绘制垂直分割线
         */
        private void drawVertical(Canvas canvas, RecyclerView parent) {
            int left = parent.getPaddingLeft() + mMarginLeft;
            int right = parent.getMeasuredWidth() - parent.getPaddingRight() - mMarginRight;
            int childSize = parent.getChildCount();
            for (int i = 0; i < childSize; i++) {
                View child = parent.getChildAt(i);
                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
                int top = child.getBottom() + layoutParams.bottomMargin;
                int bottom = top + mDividerSize;
    
                if (mDividerDrawable != null) {
                    //如果是图片分割线,绘制图片
                    mDividerDrawable.setBounds(left, top, right, bottom);
                    mDividerDrawable.draw(canvas);
                } else {
                    //绘制矩形
                    canvas.drawRect(left, top, right, bottom, mPaint);
                }
            }
        }
    
        /**
         * 绘制横向水平分割线
         */
        private void drawHorizontal(Canvas canvas, RecyclerView parent) {
            int top = parent.getPaddingTop();
            int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom();
            int childSize = parent.getChildCount();
            for (int i = 0; i < childSize; i++) {
                View child = parent.getChildAt(i);
                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
                int left = child.getRight() + layoutParams.rightMargin;
                int right = left + mDividerSize;
    
                if (mDividerDrawable != null) {
                    //如果是图片分割线,绘制图片
                    mDividerDrawable.setBounds(left, top, right, bottom);
                    canvas.drawPaint(mPaint);
                    mDividerDrawable.draw(canvas);
                } else {
                    //绘制矩形
                    canvas.drawRect(left, top, right, bottom, mPaint);
                }
            }
        }
    
        /**
         * 设置item分割线的size
         */
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            if (mOrientation == LinearLayoutManager.VERTICAL) {
                outRect.set(0, 0, 0, mDividerSize);
            } else {
                outRect.set(0, 0, mDividerSize, 0);
            }
        }
    }
    

    PowerfulRecyclerView.java

    
    /**
     * @author wangtt
     * @description: 对RecyclerView进行封装
     * @date 2017/6/27  14:10
     */
    
    public class PowerfulRecyclerView extends RecyclerView {
    
        private Context mContext;
    
        //分割线的颜色
        private int mDividerColor;
        //分割线的大小
        private int mDividerSize = 1;
        //分割线的drawable
        private Drawable mDividerDrawable;
        //是否使用瀑布流布局,默认不是
        private boolean mUseStaggerLayout;
        //列数,默认为1
        private int mNumColumns = 1;
        //RecyclerView的方向,默认为垂直方向
        private int mOrientation = LinearLayoutManager.VERTICAL;
    
        private int mMarginLeft;
        private int mMarginRight;
    
        private LayoutManager mLayoutManager;
        private DividerDecoration mDividerDecoration;
        private Drawable mItemDrawable;
    
    
        public PowerfulRecyclerView(Context context) {
            this(context,null);
        }
    
        public PowerfulRecyclerView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public PowerfulRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
    
            mContext = context;
    
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PowerfulRecyclerView);
    
            mDividerColor = ta.getColor(R.styleable.PowerfulRecyclerView_dividerColor, Color.parseColor("#ffd8d8d8"));
            mDividerSize = ta.getDimensionPixelSize(R.styleable.PowerfulRecyclerView_dividerSize, UIUtils.dip2Px(1));
    
            mDividerDrawable = ta.getDrawable(R.styleable.PowerfulRecyclerView_dividerDrawable);
    
            mUseStaggerLayout = ta.getBoolean(R.styleable.PowerfulRecyclerView_useStaggerLayout, mUseStaggerLayout);
            mNumColumns = ta.getInt(R.styleable.PowerfulRecyclerView_numColumns,mNumColumns);
    
            mOrientation = ta.getInt(R.styleable.PowerfulRecyclerView_rvOrientation, mOrientation);
    
            mMarginLeft = ta.getDimensionPixelSize(R.styleable.PowerfulRecyclerView_dividerMarginLeft, 0);
            mMarginRight = ta.getDimensionPixelSize(R.styleable.PowerfulRecyclerView_dividerMarginRight, 0);
    
            ta.recycle();
    
            setLayoutManager();
            setDivider();
        }
    
        /**
         * 设置layoutManager
         */
        private void setLayoutManager() {
            if (!mUseStaggerLayout){
                //不是瀑布流布局,即是列表或网格布局
                if (mOrientation == LinearLayoutManager.VERTICAL){
                    mLayoutManager =  new GridLayoutManager(mContext, mNumColumns);
                }else{
                    mLayoutManager = new GridLayoutManager(mContext, mNumColumns,mOrientation,false);
                }
            }else{
                //瀑布流布局
                mLayoutManager = new StaggeredGridLayoutManager(mNumColumns,mOrientation);
            }
    
            setLayoutManager(mLayoutManager);
        }
    
        /**
         * 设置分割线
         */
        private void setDivider() {
            if (mDividerDrawable == null){
                //绘制颜色分割线
                mDividerDecoration = new DividerDecoration(mContext, mOrientation,mDividerColor, mDividerSize,mMarginLeft,mMarginRight);
            }else{
                //绘制图片分割线
                mDividerDecoration = new DividerDecoration(mContext,mOrientation,mDividerDrawable,mDividerSize,mMarginLeft,mMarginRight);
            }
            this.addItemDecoration(mDividerDecoration);
        }
    }
    
    

    TipView.java

    
    
    /**
     * @author wangtt
     * @description: 顶部提示的View
     * @date 2017/6/23  15:57
     */
    
    public class TipView extends LinearLayout {
    
        private Context mContext;
    
        private int mBackGroundColor;
        private int mTextColor;
        private String mText;
        private int mTextSize;
        private TextView mTvTip;
    
        //显示所停留的时间
        private int mStayTime = 2000;
        private boolean isShowing;
        private Handler mHandler = new Handler();
    
        public TipView(Context context) {
            this(context,null);
        }
    
        public TipView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public TipView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            mContext = context;
    
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TipView);
            mBackGroundColor = ta.getColor(R.styleable.TipView_tipBackgroundColor, Color.parseColor("#ffffff"));
            mTextColor = ta.getColor(R.styleable.TipView_tipTextColor, Color.parseColor("#ffffff"));
            mText = ta.getString(R.styleable.TipView_tipText);
            mTextSize = ta.getDimensionPixelSize(R.styleable.TipView_tipTextSize, UIUtils.sp2px(context, 12));
            ta.recycle();
    
            init();
        }
    
        private void init() {
            setGravity(Gravity.CENTER);
            setBackgroundColor(mBackGroundColor);//设置背景色
    
            mTvTip = new TextView(mContext);
            mTvTip.setGravity(Gravity.CENTER);
            mTvTip.getPaint().setTextSize(mTextSize);
            mTvTip.setTextColor(mTextColor);
            mTvTip.setText(mText);
    
            addView(mTvTip);
        }
    
        public void show(String content){
            if (TextUtils.isEmpty(content)){
                show();
                return;
            }
            mTvTip.setText(content);//设置内容
            show();
        }
    
        public void show(){
            if (isShowing){
                return;
            }
    
            isShowing = true;
    
            setVisibility(VISIBLE);
    
            AnimatorSet animatorSet = new AnimatorSet();
            ObjectAnimator scaleX = ObjectAnimator.ofFloat(mTvTip, "scaleX", 0, 1f);
            ObjectAnimator scaleY = ObjectAnimator.ofFloat(mTvTip, "scaleY", 0, 1f);
    
            animatorSet.setDuration(500);
            animatorSet.play(scaleX).with(scaleY);
            animatorSet.start();
    
            animatorSet.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {
    
                }
    
                @Override
                public void onAnimationEnd(Animator animation) {
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                           hide();
                        }
                    },mStayTime);
                }
    
                @Override
                public void onAnimationCancel(Animator animation) {
    
                }
    
                @Override
                public void onAnimationRepeat(Animator animation) {
    
                }
           });
        }
    
        /**隐藏,收起*/
        private void hide() {
            TranslateAnimation  hideAnim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
                    Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF
                    ,0.0f,Animation.RELATIVE_TO_SELF,-1.0f);
    
            hideAnim.setDuration(300);
            startAnimation(hideAnim);
            hideAnim.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
    
                }
    
                @Override
                public void onAnimationEnd(Animation animation) {
                    setVisibility(GONE);
                    isShowing = false;
                    mTvTip.setText(mText); //重新设置回原来的内容
                }
    
                @Override
                public void onAnimationRepeat(Animation animation) {
    
                }
            });
        }
    }
    
    
    • 使用
      1.在布局文件里引入自定义的TipView(刷新时,头部的提醒view),BGARefreshLayout(自定义上拉刷新Layout),PowerfulRecyclerView(封装好的RecyclerView)
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="@color/cffffff">
    
        <com.weavey.loading.lib.LoadingLayout
            android:id="@+id/loading"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">
    
                <com.app.field.cicada.customview.powerfulrecyclerview.TipView
                    android:id="@+id/tip_view"
                    android:layout_width="match_parent"
                    android:layout_height="30dp"
                    android:visibility="gone"
                    app:tipBackgroundColor="@color/cd5e8f6"
                    app:tipText="网络不可用"
                    app:tipTextColor="@color/c4592C6"
                    app:tipTextSize="14sp"></com.app.field.cicada.customview.powerfulrecyclerview.TipView>
    
                <com.app.field.cicada.customview.powerfulrecyclerview.BGARefreshLayout
                    android:id="@+id/refresh_layout"
                    android:layout_width="match_parent"
                    android:layout_height="0dp"
                    android:layout_weight="1">
    
                    <FrameLayout
                        android:id="@+id/fl_content"
                        android:layout_width="match_parent"
                        android:layout_height="0dp"
                        android:layout_weight="1">
    
                        <com.app.field.cicada.customview.powerfulrecyclerview.PowerfulRecyclerView
                            android:id="@+id/rv_news"
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            app:dividerColor="@color/cf5f5f5"
                            app:dividerSize="@dimen/dp_9" />
    
                    </FrameLayout>
    
                </com.app.field.cicada.customview.powerfulrecyclerview.BGARefreshLayout>
            </LinearLayout>
        </com.weavey.loading.lib.LoadingLayout>
    </LinearLayout>
    

    2.在需要使用的地方进行初始化工作,可封装在父类里供每个界面使用。

      /*初始化刷新工具*/
        public void initRefreshView(BGARefreshLayout refreshLayout,boolean isCanLoadMore,boolean isCanRefresh){
            // 设置下拉刷新和上拉加载更多的风格     参数1:应用程序上下文,参数2:是否具有上拉加载更多功能
            BGANormalRefreshViewHolder refreshViewHolder = new BGANormalRefreshViewHolder(getActivity(), isCanLoadMore);
    //        // 设置下拉刷新
            refreshViewHolder.setRefreshViewBackgroundColorRes(R.color.ce0e0e0);//背景色
            refreshViewHolder.setPullDownRefreshText(getActivity().getResources().getString(R.string.refresh_pull_down_text));//下拉的提示文字
            refreshViewHolder.setReleaseRefreshText(getActivity().getResources().getString(R.string.refresh_release_text));//松开的提示文字
            refreshViewHolder.setRefreshingText(getActivity().getResources().getString(R.string.refresh_ing_text));//刷新中的提示文字
            refreshViewHolder.setLoadingMoreText("加载更多");
            // 设置下拉刷新和上拉加载更多的风格
            refreshLayout.setIsShowLoadingMoreView(true);
            refreshLayout.setRefreshViewHolder(refreshViewHolder);//是否显示加载更多footerview
            refreshLayout.setPullDownRefreshEnable(isCanRefresh);//设置是否可以刷新
        }
    

    3.设置下拉刷新上拉加载更多代理
    mRefreshLayout.setDelegate(this);
    4.重写加载更多和刷新方法

     @Override
        public void onBGARefreshLayoutBeginRefreshing(BGARefreshLayout refreshLayout) {
             //刷新操作
        }
    
      @Override
        public boolean onBGARefreshLayoutBeginLoadingMore(BGARefreshLayout refreshLayout) {
           //加载更多操作
            return false;
        }
    

    5.停止刷新和加载更多的操作

      mRefreshLayout.endRefreshing();
      mRefreshLayout.endLoadingMore();
    

    相关文章

      网友评论

          本文标题:RecyclerView+BGARefreshLayout实现自

          本文链接:https://www.haomeiwen.com/subject/dhnczxtx.html