美文网首页Android-recyclerview
recyclerview 单独页面翻页效果和 此消彼长的指示器

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

作者: Ad大成 | 来源:发表于2021-02-20 15:44 被阅读0次

    首先单个我们知道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/32714835https://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 单独页面翻页效果和 此消彼长的指示器

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