recyclerview 单独页面翻页效果和 此消彼长的指示器

首先单个我们知道recyclerview翻页效果一般是配合viewPager来完成的 但是如何做到单个fragment无需viewPager也能完成操作呢!

这个时候就需要谷歌的官方推荐的SnapHelper 来完成这个需求 但是又有大神帮忙封装好了就直接拿来用就好哈哈

导入sdk implementation 'com.gcssloop.support:pagerlayoutmanager:1.3.1@aar'

 LogUtils.i(TAG,"servicefragment 列表展示 数据大小:"+data.size());
        final PagerGridLayoutManager pagerGridLayoutManager = new PagerGridLayoutManager(2, 8, PagerGridLayoutManager.HORIZONTAL);
        pagerGridLayoutManager.setPageListener(this);
        recycler_service.setLayoutManager(pagerGridLayoutManager);
        PagerGridSnapHelper pagerGridSnapHelper = new PagerGridSnapHelper();
        recycler_service.setOnFlingListener(null);
        pagerGridSnapHelper.attachToRecyclerView(recycler_service);
//        initTypeViewPager(2,8,list);
        AllAppAdapter allAppAdapter = new AllAppAdapter(applicationContext, data);
        recycler_service.setAdapter(allAppAdapter);
        int dataPage = (int) Math.ceil((double)data.size() / 16); //(double)细节 如果是整数不会向上取整

        LogUtils.i(TAG,"dataPage="+dataPage);

        mIndicator.setPageNum(dataPage);

        recycler_service.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);



                int indexNum=2;

                int prePageFirstPos = pagerGridLayoutManager.findPrePageFirstPos();
                int indicatorIndex=0;
                if (indexNum > 1) {
                    indicatorIndex = (prePageFirstPos / 8) % indexNum;
                    if (prePageFirstPos % 8 > 0) {
                        indicatorIndex = indicatorIndex == indexNum ? 0 : indicatorIndex + 1;
                    }

                    LogUtils.i(TAG,"addOnScrollListener-> indicatorIndex="+indicatorIndex);
                    mIndicator.onPageScrolled(2, 0.0f, recyclerView);
                }


//                mIndicator.onPageScrolled(indicatorIndex,0.0f,dx);

            }
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

        });

以上注意setOnFlingListener(null) 这个方法 必须设置为null 查看源码后发现有的时候会找不到recyclerview实例 导致崩溃的问题

下面是自定义指示器的代码 有点乱哈 没有优化的版本

public class SimpleLineIndicator extends View {
    private static final String TAG ="SimpleCircleIndicator" ;
    Paint circlePaint;

    private int pageNum;
    private float scrollPercent = 0f;
    private int currentPosition;
    private int gapSize;


    private float radius;
    private int colorOn;
    private int colorOff;

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

    public SimpleLineIndicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public SimpleLineIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
//        radius = SystemUtils.dp2px( getContext(),3);/**/
        circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        colorOn = Color.WHITE;
        colorOff = Color.parseColor("#888888");
//        gapSize = SystemUtils.dp2px( getContext(),10);
        circlePaint.setStrokeCap(Paint.Cap.ROUND);
        circlePaint.setStrokeWidth(SystemUtils.dp2px(4));
        circlePaint.setStyle(Paint.Style.STROKE);
        circlePaint.setAntiAlias(true);


    }

    public void setSelectDotColor(int colorOn) {
        this.colorOn = colorOn;
    }

    public void setUnSelectDotColor(int colorOff) {
        this.colorOff = colorOff;
    }

    private RecyclerView mRecyclerView;

    public void onPageScrolled(int position, float percent, RecyclerView recyclerView) {
        scrollPercent = percent;
        currentPosition = position;
        mRecyclerView=recyclerView;
        invalidate();
    }

    private ViewPager viewPager;

    public void setViewPager(ViewPager viewPager) {
        this.viewPager = viewPager;
        if (null != viewPager) {
            pageNum = viewPager.getAdapter().getCount();
        }
    }

    protected final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
   private float mLongIndicatorItemLength=SystemUtils.dp2px(100);
   private float mShortIndicatorItemLength=SystemUtils.dp2px(48);
   private float mIndicatorItemPadding=SystemUtils.dp2px(24);
    private int[] mPageScrolls;
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (pageNum <= 0) {
            return;
        }
        PagerGridLayoutManager layoutManager = (PagerGridLayoutManager) mRecyclerView.getLayoutManager();

        if (layoutManager==null){
            LogUtils.i(TAG,"layoutManager is null ");
            return;
        }


        //计算 指示器长和短的长度和
        float totalLength = mLongIndicatorItemLength + mShortIndicatorItemLength * (pageNum - 1);
        //计算指示器外边距总距离
        float paddingBetweenItems = Math.max(0, pageNum - 1) *  mIndicatorItemPadding;

        //指示器真正的长度
        float indicatorTotalWidth = totalLength + paddingBetweenItems;

        LogUtils.i(TAG,"onDraw   totalLength="+totalLength+"---->paddingBetweenItems ="+paddingBetweenItems+"----->indicatorTotalWidth="+indicatorTotalWidth+"----->getWidth="+getWidth());

        //x y 起始位置
        float indicatorStartX;
        float indicatorPosY;
        indicatorStartX=(getWidth()-indicatorTotalWidth)/2F;

        indicatorPosY=getHeight()-18;


        float progress;
        LogUtils.i(TAG,"onDraw   startX="+indicatorStartX+"onDraw   startY="+indicatorPosY);

        int offsetX = layoutManager.getOffsetX();
        int width = layoutManager.getWidth();
        int currentPage=offsetX/width;

        if (offsetX % width > 0){
            currentPage+=1;
        }
        float f;
        f = (layoutManager.getOffsetX() - currentPage * mRecyclerView.getWidth()) / (float) (mRecyclerView.getWidth());

        progress=mInterpolator.getInterpolation(f);


        int nextPage;

        int pageSize = layoutManager.getItemCount();
        mPageScrolls = new int[pageSize];
        for (int i = 0; i < pageSize; i++) {
            mPageScrolls[i]=layoutManager.getWidth()*i;
        }
        if (offsetX - mPageScrolls[currentPage] > 0) {
            nextPage = currentPage + 1;
        } else if (offsetX -  mPageScrolls[currentPage] < 0) {
            nextPage = currentPage - 1;
        } else {
            nextPage = currentPage;
        }




        LogUtils.i(TAG,"onDraw  progress= "+progress +"---->offsetX="+offsetX+"---->pageSize="+pageSize+"----->nextPage="+nextPage);


        //需要获取当前页 参数

        drawInactiveIndicators(canvas, indicatorStartX, indicatorPosY, currentPage, progress, pageNum, nextPage);


//
//        float left = (getWidth() - (pageNum - 1) * gapSize) * 0.5f;
//        LogUtils.i(TAG,"onDraw ----> left="+left+"[getWidth="+getWidth()+"]");
//        float height = getHeight() * 0.5f;
//        LogUtils.i(TAG,"height="+height);
//
//        circlePaint.setColor(colorOff);
//        for (int i = 0; i < pageNum; i++) {
//            canvas.drawLine(left + i * gapSize, height, left + i * gapSize+50,height, circlePaint);
//
//        }
//        circlePaint.setColor(colorOn);
//        canvas.drawLine(left + currentPosition * gapSize + gapSize * scrollPercent, height, left + currentPosition * gapSize + gapSize * scrollPercent+50,height, circlePaint);
    }

    public void setPageNum(int nums){
        pageNum = nums;
    }






    private void drawInactiveIndicators(Canvas c, float indicatorStartX, float indicatorPosY,
                                        int highlightPosition, float progress, int pageCount, int nextPage) {
        int blendColor = ColorUtils.blendARGB(colorOn, colorOff, progress);
        int blendColor1 = ColorUtils.blendARGB(colorOn, colorOff, 1 - progress);

        final float itemWidth = mLongIndicatorItemLength + mIndicatorItemPadding;
        float start;
//        if (canScrollHorizontally) {
            start = indicatorStartX;
//        } else {
//            start = indicatorPosY;
//        }
        if (progress == 0F) {
            for (int i = 0; i < pageCount; i++) {
                if (i == highlightPosition) {
                    circlePaint.setColor(colorOn);
//                    if (canScrollHorizontally) {
                        c.drawLine(start, indicatorPosY, start + mLongIndicatorItemLength, indicatorPosY, circlePaint);
                        start += itemWidth;

                        LogUtils.i(TAG,"i==highlightPosition  true----->start=" +start+"----->itemWidth="+itemWidth+"---->start + mLongIndicatorItemLength="+start + mLongIndicatorItemLength);
//                    } else {
//                        c.drawLine(indicatorStartX, start, indicatorStartX, start + mLongIndicatorItemLength, mPaint);
//                        start += itemWidth;
//                    }
                } else {
                    circlePaint.setColor(colorOff);
//                    if (canScrollHorizontally) {
                        c.drawLine(start, indicatorPosY, start + mShortIndicatorItemLength, indicatorPosY, circlePaint);
                        start += mShortIndicatorItemLength + mIndicatorItemPadding;


                    LogUtils.i(TAG,"i==highlightPosition false----->start=" +start+"----->itemWidth="+itemWidth+"---->start + mShortIndicatorItemLength="+start + mShortIndicatorItemLength);
//                    } else {
//                        c.drawLine(indicatorStartX, start, indicatorStartX, start + mShortIndicatorItemLength, mPaint);
//                        start += mShortIndicatorItemLength + mIndicatorItemPadding;
//                    }
                }
            }
        } else {
            float partialLength = mShortIndicatorItemLength * progress;
            for (int i = 0; i < pageCount; i++) {
                if (nextPage > highlightPosition) {
                    if (i == highlightPosition) {
                        circlePaint.setColor(blendColor);
//                        if (canScrollHorizontally) {
                            c.drawLine(start, indicatorPosY, start + mLongIndicatorItemLength - partialLength, indicatorPosY, circlePaint);
                            start += itemWidth;
//                        } else {
//                            c.drawLine(indicatorStartX, start, indicatorStartX, start + mLongIndicatorItemLength - partialLength, mPaint);
//                            start += itemWidth;
//                        }

                    } else if (i == nextPage) {
                        circlePaint.setColor(blendColor1);
//                        if (canScrollHorizontally) {
                            c.drawLine(start - partialLength, indicatorPosY, start + mShortIndicatorItemLength, indicatorPosY, circlePaint);
                            start += mShortIndicatorItemLength + mIndicatorItemPadding;
//                        } else {
//                            c.drawLine(indicatorStartX, start - partialLength, indicatorStartX, start + mShortIndicatorItemLength, mPaint);
//                            start += mShortIndicatorItemLength + mIndicatorItemPadding;
//                        }
                    } else {
                        circlePaint.setColor(colorOff);
//                        if (canScrollHorizontally) {
                            c.drawLine(start, indicatorPosY, start + mShortIndicatorItemLength, indicatorPosY, circlePaint);
                            start += mShortIndicatorItemLength + mIndicatorItemPadding;
//                        } else {
//                            c.drawLine(indicatorStartX, start, indicatorStartX, start + mShortIndicatorItemLength, mPaint);
//                            start += mShortIndicatorItemLength + mIndicatorItemPadding;
//                        }
                    }
                } else {
                    if (i == highlightPosition) {
                        circlePaint.setColor(blendColor);
//                        if (canScrollHorizontally) {
                            c.drawLine(start + partialLength, indicatorPosY, start + mLongIndicatorItemLength, indicatorPosY, circlePaint);
                            start += itemWidth;
//                        } else {
//                            c.drawLine(indicatorStartX, start + partialLength, indicatorStartX, start + mLongIndicatorItemLength, mPaint);
//                            start += itemWidth;
//                        }
                    } else if (i == nextPage) {
                        circlePaint.setColor(blendColor1);
//                        if (canScrollHorizontally) {
                            c.drawLine(start, indicatorPosY, start + mShortIndicatorItemLength + partialLength, indicatorPosY, circlePaint);
                            start += mShortIndicatorItemLength + mIndicatorItemPadding;
//                        } else {
//                            c.drawLine(indicatorStartX, start, indicatorStartX, start + mShortIndicatorItemLength + partialLength, mPaint);
//                            start += mShortIndicatorItemLength + mIndicatorItemPadding;
//                        }
                    } else {
                        circlePaint.setColor(colorOff);
//                        if (canScrollHorizontally) {
                            c.drawLine(start, indicatorPosY, start + mShortIndicatorItemLength, indicatorPosY, circlePaint);
                            start += mShortIndicatorItemLength + mIndicatorItemPadding;
//                        } else {
//                            c.drawLine(indicatorStartX, start, indicatorStartX, start + mShortIndicatorItemLength, mPaint);
//                            start += mShortIndicatorItemLength + mIndicatorItemPadding;
//                        }
                    }
                }
            }
        }
    }


}

这里面需要注意的几个地方protected final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();

我想了解动画的朋友应该对插值器并不陌生, Interpolator 被用来修饰动画效果,定义动画的变化率,可以使存在的动画效果accelerated(加速),decelerated(减速),repeated(重复),bounced(弹跳)等。而AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢,在中间的时候加速。

具体可以去https://blog.csdn.net/qeqeqe236/article/details/32714835和https://blog.csdn.net/carson_ho/article/details/72863901研究一下

f = (layoutManager.getOffsetX() - currentPage * mRecyclerView.getWidth()) / (float) (mRecyclerView.getWidth());

progress=mInterpolator.getInterpolation(f);

layoutManager.getOffsetX() 列表的偏移量(起始绘制点)必须减去当前页面的列表宽度 因为有可能你滑动到第二页或者第三页这个偏移量会累加的。比如你的屏幕是1000px 那么当你滑动到第二页的时候你当前的偏移量就是1000px 滑动到第三页的时候是2000px。

而这个f 就是动画的速率 0为动画开始 1为结束 0-1之间的速率 后面可以根据这个速率计算出移动progress从而借助这个int blendColor = ColorUtils.blendARGB(colorOn, colorOff, progress);这个方法来根据速率开始时和结束时变换我们想要的颜色。

好了不知道你们看没看懂哈 反正我是记录一下!

你可能感兴趣的:(recyclerview 单独页面翻页效果和 此消彼长的指示器)