recyclerview 單獨(dú)頁(yè)面翻頁(yè)效果和 此消彼長(zhǎng)的指示器

首先單個(gè)我們知道recyclerview翻頁(yè)效果一般是配合viewPager來(lái)完成的 但是如何做到單個(gè)fragment無(wú)需viewPager也能完成操作呢!

這個(gè)時(shí)候就需要谷歌的官方推薦的SnapHelper 來(lái)完成這個(gè)需求 但是又有大神幫忙封裝好了就直接拿來(lái)用就好哈哈

導(dǎo)入sdk implementation 'com.gcssloop.support:pagerlayoutmanager:1.3.1@aar'

 LogUtils.i(TAG,"servicefragment 列表展示 數(shù)據(jù)大性侣濉:"+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)細(xì)節(jié) 如果是整數(shù)不會(huì)向上取整

        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) 這個(gè)方法 必須設(shè)置為null 查看源碼后發(fā)現(xiàn)有的時(shí)候會(huì)找不到recyclerview實(shí)例 導(dǎo)致崩潰的問(wèn)題

下面是自定義指示器的代碼 有點(diǎn)亂哈 沒(méi)有優(yōu)化的版本

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;
        }


        //計(jì)算 指示器長(zhǎng)和短的長(zhǎng)度和
        float totalLength = mLongIndicatorItemLength + mShortIndicatorItemLength * (pageNum - 1);
        //計(jì)算指示器外邊距總距離
        float paddingBetweenItems = Math.max(0, pageNum - 1) *  mIndicatorItemPadding;

        //指示器真正的長(zhǎng)度
        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);


        //需要獲取當(dāng)前頁(yè) 參數(shù)

        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;
//                        }
                    }
                }
            }
        }
    }


}

這里面需要注意的幾個(gè)地方protected final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();

我想了解動(dòng)畫的朋友應(yīng)該對(duì)插值器并不陌生, Interpolator 被用來(lái)修飾動(dòng)畫效果,定義動(dòng)畫的變化率撵术,可以使存在的動(dòng)畫效果accelerated(加速),decelerated(減速),repeated(重復(fù)),bounced(彈跳)等话瞧。而AccelerateDecelerateInterpolator 在動(dòng)畫開始與結(jié)束的地方速率改變比較慢嫩与,在中間的時(shí)候加速。

具體可以去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() 列表的偏移量(起始繪制點(diǎn))必須減去當(dāng)前頁(yè)面的列表寬度 因?yàn)橛锌赡苣慊瑒?dòng)到第二頁(yè)或者第三頁(yè)這個(gè)偏移量會(huì)累加的交排。比如你的屏幕是1000px 那么當(dāng)你滑動(dòng)到第二頁(yè)的時(shí)候你當(dāng)前的偏移量就是1000px 滑動(dòng)到第三頁(yè)的時(shí)候是2000px划滋。

而這個(gè)f 就是動(dòng)畫的速率 0為動(dòng)畫開始 1為結(jié)束 0-1之間的速率 后面可以根據(jù)這個(gè)速率計(jì)算出移動(dòng)progress從而借助這個(gè)int blendColor = ColorUtils.blendARGB(colorOn, colorOff, progress);這個(gè)方法來(lái)根據(jù)速率開始時(shí)和結(jié)束時(shí)變換我們想要的顏色。

好了不知道你們看沒(méi)看懂哈 反正我是記錄一下埃篓!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末处坪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌稻薇,老刑警劉巖嫂冻,帶你破解...
    沈念sama閱讀 211,496評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異塞椎,居然都是意外死亡桨仿,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,187評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門案狠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)服傍,“玉大人,你說(shuō)我怎么就攤上這事骂铁〈盗悖” “怎么了?”我有些...
    開封第一講書人閱讀 157,091評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵拉庵,是天一觀的道長(zhǎng)灿椅。 經(jīng)常有香客問(wèn)我,道長(zhǎng)钞支,這世上最難降的妖魔是什么茫蛹? 我笑而不...
    開封第一講書人閱讀 56,458評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮烁挟,結(jié)果婚禮上婴洼,老公的妹妹穿的比我還像新娘。我一直安慰自己撼嗓,他們只是感情好柬采,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,542評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著且警,像睡著了一般粉捻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上振湾,一...
    開封第一講書人閱讀 49,802評(píng)論 1 290
  • 那天杀迹,我揣著相機(jī)與錄音,去河邊找鬼押搪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛浅碾,可吹牛的內(nèi)容都是我干的大州。 我是一名探鬼主播,決...
    沈念sama閱讀 38,945評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼垂谢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼厦画!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,709評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤根暑,失蹤者是張志新(化名)和其女友劉穎力试,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體排嫌,經(jīng)...
    沈念sama閱讀 44,158評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡畸裳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,502評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淳地。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怖糊。...
    茶點(diǎn)故事閱讀 38,637評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖颇象,靈堂內(nèi)的尸體忽然破棺而出伍伤,到底是詐尸還是另有隱情,我是刑警寧澤遣钳,帶...
    沈念sama閱讀 34,300評(píng)論 4 329
  • 正文 年R本政府宣布扰魂,位于F島的核電站,受9級(jí)特大地震影響蕴茴,放射性物質(zhì)發(fā)生泄漏劝评。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,911評(píng)論 3 313
  • 文/蒙蒙 一荐开、第九天 我趴在偏房一處隱蔽的房頂上張望付翁。 院中可真熱鬧,春花似錦晃听、人聲如沸百侧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,744評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)佣渴。三九已至,卻和暖如春初斑,著一層夾襖步出監(jiān)牢的瞬間辛润,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,982評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工见秤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留砂竖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,344評(píng)論 2 360
  • 正文 我出身青樓鹃答,卻偏偏與公主長(zhǎng)得像乎澄,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子测摔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,500評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容