Backlight87
8/24/2017 - 7:20 PM

垂直view page上拉加载更多 //这里是依赖垂直的viewpage的那个类的

垂直view page上拉加载更多 //这里是依赖垂直的viewpage的那个类的

/**
 * 继承垂直的view page,实现最后一页弹性伸缩通知加载更多的功能
 */
public class LoadMoreViewPager extends VerticalViewPager {
    // ===========================================================
    // Constants
    // ===========================================================
    /**
     * 控制弹性的最大的距离
     */
    final static int DEFAULT_OVERSCROLL_TRANSLATION = 650;

    /**
     * 动画的时间
     */
    final private static int DEFAULT_OVERSCROLL_ANIMATION_DURATION = 300;
    private final static int INVALID_POINTER_ID = -1;

    // ===========================================================
    // Fields
    // ===========================================================
    final private OverscrollEffect mOverscrollEffect = new OverscrollEffect();
    final private Camera mCamera = new Camera();
    private OnPageChangeListener mScrollListener;
    private float mLastMotionY;
    private int mActivePointerId;
    private int mScrollPosition;
    private float mScrollPositionOffset;
    final private int mTouchSlop;
    private LoadMoreFromBounceViewPage loadMore;
    //高度,默认是上面的150
    private float mOverscrollTranslation;
    //持续时间默认的是上面的400ms
    private int mOverscrollAnimationDuration;
    //用来过滤操作的
    private boolean IsSend = false;
    private boolean IsFromTouch = false;
    private int mLastPosition = 0;

    public LoadMoreViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        setStaticTransformationsEnabled(true);
        final ViewConfiguration configuration = ViewConfiguration.get(context);
        // getScaledTouchSlop是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件
        mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
        super.setOnPageChangeListener(new MyOnPageChangeListener());
        init(attrs);
    }
    // ===========================================================
    // Override Methods
    // ===========================================================

    @Override
    public void setOnPageChangeListener(OnPageChangeListener listener) {
        mScrollListener = listener;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        try {
            return super.dispatchTouchEvent(ev);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            return false;
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public void scrollBy(@Px int x, @Px int y) {
        super.scrollBy(x, y);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean callSuper = false;
        final int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                callSuper = true;
                mLastMotionY = ev.getY();
                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                if (mActivePointerId != INVALID_POINTER_ID) {
                    // Scroll to follow the motion event
                    final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
                    final float y = MotionEventCompat.getY(ev, activePointerIndex);
                    final float deltay = mLastMotionY - y;
                    //对于view page永远getScrollY获取的值是0
                    //final float oldScrolly = getScrollY();
                    final int height = getHeight();
                    final int HeightWithMargin = height + getPageMargin();
                    final int lastItemIndex = getAdapter().getCount() - 1;
                    final int currentItemIndex = getCurrentItem();
                    final float bottom1Bound = Math.max(0, (currentItemIndex - 1) * HeightWithMargin);
                    float oldScrolly = (currentItemIndex) * HeightWithMargin + getTop();
                    final float top1Bound = Math.min(currentItemIndex + 1, lastItemIndex) * HeightWithMargin;
                    final float scrollY = oldScrolly + deltay;
                    if (mScrollPositionOffset == 0) {
                        if (scrollY < bottom1Bound) {
                            if (bottom1Bound == 0) {
                                final float over = deltay + mTouchSlop;
                                mOverscrollEffect.setPull(over / height);
                                //第一页下拉刷新
                            }
                        } else if (scrollY > top1Bound) {
                            //最后一个上拉加载更多
                            if (top1Bound == lastItemIndex * HeightWithMargin) {
                                final float over = scrollY - top1Bound - mTouchSlop;
                                // 在这里实现调用加载的动作,然后在监听里取消加载的图标的显示
                                // ((MainActivity) context1).show();
                                IsFromTouch = true;
                                mOverscrollEffect.setPull(over / height);
                            }
                        }
                    } else {
                        mLastMotionY = y;
                    }
                } else {
                    mOverscrollEffect.onRelease();
                }
                break;
            }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                callSuper = true;
                mActivePointerId = INVALID_POINTER_ID;
                mOverscrollEffect.onRelease();
                break;
            }
        }

        if (mOverscrollEffect.isOverScrolling() && !callSuper) {
            return true;
        } else {
            return super.onTouchEvent(ev);
        }
    }

    @Override
    protected boolean getChildStaticTransformation(View child, Transformation t) {
        if (child.getHeight() == 0) {
            return false;
        }
        final int position = child.getTop() / child.getHeight();
        final boolean isFirstOrLast = position == 0 || (position == getAdapter().getCount() - 1);
        if (mOverscrollEffect.isOverScrolling() && isFirstOrLast) {
            final float dx = getWidth() / 2;
            final int dy = getHeight() / 2;
            t.getMatrix().reset();
            final float translateY = mOverscrollTranslation * (mOverscrollEffect.mOverscroll > 0 ? Math.min(mOverscrollEffect.mOverscroll, 1) : Math.max(mOverscrollEffect.mOverscroll, -1));
            mCamera.save();
            mCamera.translate(0, translateY, 0);
            mCamera.getMatrix(t.getMatrix());
            mCamera.restore();
            //在这里通过矩阵的变换实现平移的操作,pre是前乘
            t.getMatrix().preTranslate(-dx, -dy);
            t.getMatrix().postTranslate(dx, dy);
            if (getChildCount() == 1) {
                this.invalidate();
            } else {
                child.invalidate();
            }
            return true;
        }
        return false;
    }

    // ===========================================================
    // Define Methods
    // ===========================================================
    private void init(AttributeSet attrs) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.LoadMoreViewPager);
        mOverscrollTranslation = a.getDimension(R.styleable.LoadMoreViewPager_overscroll_translation, DEFAULT_OVERSCROLL_TRANSLATION);
        mOverscrollAnimationDuration = a.getInt(R.styleable.LoadMoreViewPager_overscroll_animation_duration, DEFAULT_OVERSCROLL_ANIMATION_DURATION);
        a.recycle();
    }

    private void invalidateVisibleChilds() {
        for (int i = 0; i < getChildCount(); i++) {
            //请求重绘所有的Child
            getChildAt(i).invalidate();

        }
    }


    //设置需要刷新时候的操作
    public void setLoadMorelisten(LoadMoreFromBounceViewPage loadMore) {
        this.loadMore = loadMore;
    }


    // ===========================================================
    // Inner and Anonymous Classes
    // ===========================================================

    /**
     * 弹性的动画
     */
    private class OverscrollEffect {
        private float mOverscroll;
        private Animator mAnimator;

        /**
         * 是否到尽头要开始动画了
         *
         * @param deltaDistance [0..1] 0->no overscroll, 1>full overscroll
         */
        private void setPull(final float deltaDistance) {
            mOverscroll = deltaDistance;
            invalidateVisibleChilds();
        }


        /**
         * 当手指离开的时候回调返回到原来的地方
         */
        private void onRelease() {
            if (mAnimator != null && mAnimator.isRunning()) {
                mAnimator.cancel();
            } else {
                myStartAnimation(0);
            }
        }

        private void myStartAnimation(final float target) {
            //三个参数,操纵的view,动画名称,滑出去的位置,回来的位置
            mAnimator = ObjectAnimator.ofFloat(this, "pull", mOverscroll, target);

            mAnimator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {

                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    if (IsSend && IsFromTouch) {
                        mAnimator.pause();
                        loadMore.loadMore();
                        IsSend = false;
                        IsFromTouch = false;
                    }
                    IsSend = true;
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                    IsSend = true;
                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });
            mAnimator.setInterpolator(new DecelerateInterpolator());
            final float scale = Math.abs(target - mOverscroll);
            mAnimator.setDuration((long) (mOverscrollAnimationDuration * scale));
            mAnimator.start();
        }

        /**
         * 这里判断是不是第一个或者最后一个
         *
         * @return true 是,否则不是
         */
        private boolean isOverScrolling() {
          /*  if (mScrollPosition == 0 && mOverscroll < 0) {
                return true;
            }*/
            if (getAdapter() != null) {//getAdapter容易为空导致下面crash
                final boolean isLast = (getAdapter().getCount() - 1) == mScrollPosition;
                if (isLast && mOverscroll > 0) {
                    return true;
                }
                return false;
            }
            return false;
        }
    }

    private class MyOnPageChangeListener implements OnPageChangeListener {

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if (mScrollListener != null) {
                mScrollListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
            }
            mScrollPosition = position;
            mScrollPositionOffset = positionOffset;
            mLastPosition = position;
            //滑动的时候重新绘制一下
            //  invalidateVisibleChilds();
        }

        @Override
        public void onPageSelected(int position) {
            if (mScrollListener != null) {
                mScrollListener.onPageSelected(position);
            }
        }

        @Override
        public void onPageScrollStateChanged(final int state) {

            if (mScrollListener != null) {
                mScrollListener.onPageScrollStateChanged(state);
            }
            if (state == SCROLL_STATE_IDLE) {
                mScrollPositionOffset = 0;
            }
        }
    }

    // ===========================================================
    // Getter & Setter
    // ===========================================================
    public int getOverscrollAnimationDuration() {
        return mOverscrollAnimationDuration;
    }

    public void setOverscrollAnimationDuration(int mOverscrollAnimationDuration) {
        this.mOverscrollAnimationDuration = mOverscrollAnimationDuration;
    }

    public float getOverscrollTranslation() {
        return mOverscrollTranslation;
    }

    public void setOverscrollTranslation(int mOverscrollTranslation) {
        this.mOverscrollTranslation = mOverscrollTranslation;
    }

    interface LoadMoreFromBounceViewPage {
        void loadMore();
    }
}

/////////////////////////////////////////////////////////



/**
 * 封装好的一个垂直展示的view page里面有下拉加载更多
 * 外界调用必须调用initViewPage()->setLoadMoreListen()->(各种设置非必选)->setAdapt()->处理完成后还得调一下loadFinish通知已经加载更多结束,方便控件进行关闭进度条类似的操作
 * Created by hsp on 2017/8/11.
 */
public class MyViewPager extends RelativeLayout implements LoadMoreViewPager.LoadMoreFromBounceViewPage {

    private LoadMoreViewPager mLoadMoreViewPager;
    private TextView loadMoreText;
    private ProgressBar loadMoreProgress;


    private RelativeLayout mRelativeLayout;
    //底部加载更多的时候显示的图片
    private Context mContext;
    private LoadMore loadMore;
    private String defaultLoadMoreText = getResources().getString(R.string.main_activity_bottom_text);
    private int defaultLoadMoreHeight = 0;

    public MyViewPager(Context context) {
        super(context);
        mContext = context;
        init();
    }

    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MyViewPager);
        if (!TextUtils.isEmpty(a.getString(R.styleable.MyViewPager_load_more_text))) {
            defaultLoadMoreText = a.getString(R.styleable.MyViewPager_load_more_text);
        }
        defaultLoadMoreHeight = (int) a.getDimension(R.styleable.MyViewPager_load_more_height, defaultLoadMoreHeight);
        a.recycle();
        mContext = context;
        init();
    }

    public MyViewPager(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;
        init();
    }

    @Override
    public void loadMore() {
        //从view page里传过来的要加载数据的操作
        //我们在这里进行加载更多UI的操作,并且如果数据操作了就什么都不显示?感觉这个ui还是要activity层控制
        mRelativeLayout.setVisibility(View.VISIBLE);
        loadMore.loadMore();
    }

    // ===========================================================
    // Define Methods
    // ===========================================================

    private void init() {
        View.inflate(mContext, R.layout.my_viewpage_layout, this);
        mLoadMoreViewPager = (LoadMoreViewPager) findViewById(R.id.my_viewpage_viewpager);
        loadMoreText = (TextView) findViewById(R.id.my_viewpage_bottom_tv);
        loadMoreProgress = (ProgressBar) findViewById(R.id.my_viewpage_bottom_progress);
        mRelativeLayout = (RelativeLayout) findViewById(R.id.my_viewpage_bottom_rl);
        reset();

    }

    public void initViewPage() {
        mLoadMoreViewPager.setPageTransformer(true, new DefaultTransformer());
        //禁止出现滑动的时候阴影效果
        mLoadMoreViewPager.setOverScrollMode(View.OVER_SCROLL_NEVER);
        mLoadMoreViewPager.setLoadMorelisten(this);
    }

    /**
     * 在设置adapt之前可以设置各种属性
     *
     * @param adapter view page的适配器
     */
    public void setAdapt(PagerAdapter adapter) {
        loadMoreText.setText(defaultLoadMoreText);
        ViewGroup.LayoutParams params = mRelativeLayout.getLayoutParams();
        ViewGroup.MarginLayoutParams marginParams = null;
        //获取view的margin设置参数
        if (params instanceof ViewGroup.MarginLayoutParams) {
            marginParams = (ViewGroup.MarginLayoutParams) params;
        } else {
            //不存在时创建一个新的参数
            //基于View本身原有的布局参数对象
            marginParams = new ViewGroup.MarginLayoutParams(params);
        }
        marginParams.setMargins(0, 0, 0, defaultLoadMoreHeight);
        mRelativeLayout.setLayoutParams(params);
        mLoadMoreViewPager.setAdapter(adapter);
    }

    //接收activity传过来的操作
    public void setLoadMoreListen(LoadMore loadMore) {
        this.loadMore = loadMore;
    }

    //这个是要传到activity层次的,给他们更新数据
    public interface LoadMore {
        void loadMore();
    }

    public void loadFinish() {
        //关闭进度条,关闭动画效果
        //先不要关
        // mRelativeLayout.setVisibility(View.GONE);
    }

    // ===========================================================
    // Getter & Setter
    // ===========================================================
    private void reset() {
        if (loadMoreText != null) {
            loadMoreText.setText(defaultLoadMoreText);
        }
    }

    public void setNoMore() {
        if (loadMoreText != null) {
            loadMoreText.setText(getResources().getString(R.string.main_activity_no_more_text));
        }
    }

    public void setCurrentItem(int position) {
        if (mLoadMoreViewPager != null) {
            mLoadMoreViewPager.setCurrentItem(position);
        }
    }

    public LoadMoreViewPager getmLoadMoreViewPager() {
        return mLoadMoreViewPager;
    }

    public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
        if (mLoadMoreViewPager != null) {
            mLoadMoreViewPager.setOnPageChangeListener(listener);
        }
    }

    public String getDefaultLoadMoreText() {
        return defaultLoadMoreText;
    }

    public void setLoadMoreText(String loadMoreText) {
        this.defaultLoadMoreText = loadMoreText;

    }

    public int getDefaultLoadMoreHeight() {
        return defaultLoadMoreHeight;
    }

    public void setLoadMoreHeight(int loadMoreHeight) {
        this.defaultLoadMoreHeight = loadMoreHeight;
    }
}






////////////////////////////////////////////////////////







<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/my_viewpage_bottom_rl"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="0dp"
       >

        <ProgressBar
            android:id="@+id/my_viewpage_bottom_progress"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="150dp" />

        <TextView
            android:id="@+id/my_viewpage_bottom_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignStart="@+id/my_viewpage_bottom_progress"
            android:layout_centerVertical="true"
            android:layout_marginLeft="50dp"
            android:text="@string/main_activity_bottom_text" />
    </RelativeLayout>

    <com.example.meitu.feedtestproject.widget.LoadMoreViewPager
        android:id="@+id/my_viewpage_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>