RecycleView滑動錨點定位

RecycleView滑動,頂部tab跟著變化位置,類似于淘寶詳情頁,效果是這樣的


Tab跟隨RecycleView滑動

1.實現(xiàn)思路

簡單講就是監(jiān)聽RecycleView的滑動,根據(jù)滑動調(diào)整tab位置。相應的監(jiān)聽tab點擊事件,滑動recycleView到相應位置。

2.滑動RecycleView調(diào)整tab位置

2.1獲得滑動位置

LayoutManager提供了獲得首個可見item的方法
int position = layoutManager.findFirstVisibleItemPosition();

2.2將滑動位置轉(zhuǎn)換為類型位置

這里我item類型有普通類型和大類的標題類型,通過instanceof判斷類型是否是我所屬的大類的標題類型,然后根據(jù)大類標題類型到頂部的距離判斷,再根據(jù)類型名稱進行定位。
然后通過getTop獲得到頂部的距離,根據(jù)距離進行分類間的跳轉(zhuǎn)。
int top = mRecyclerView.getChildAt(0).getTop();

2.3完整代碼

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                //不捕獲自動滾動,非用戶觸摸產(chǎn)生的滑動
                if (isFormTabScroll) {
                    return;
                }

                //監(jiān)聽滑動距離,改變tab選中位置
                int position = layoutManager.findFirstVisibleItemPosition();
                int realPosition = position - mAdapter.getHeaderSize();

                //因為有1個header所以>=-1
                if (realPosition >= -1 && realPosition < mAdapter.getList().size()) {
                    //通過判斷分類卡片位置定位tab
                    if (mealCardIndxList.size() == 0) {//記錄大類的流量卡片位置
                        for (int i = 0; i < mAdapter.getList().size(); i++) {
                            if (mAdapter.getList().get(i) instanceof CardFlowMeal) {
                                mealCardIndxList.add(i);
                            }
                        }
                    }

                    if (mealCardIndxList.size() + 1 == indicator.getTitles().size()) {//防止下標越界異常
                        //判斷當前item所處類定位tab
                        for (int i = 0; i < mealCardIndxList.size(); i++) {
                            if (i == 0) {
                                if (realPosition >= -1 && realPosition < mealCardIndxList.get(i)) {
                                    if (indicator.getCurrentPosition() != 0) {
                                        indicator.setCurrentItem(0);
                                        break;
                                    }
                                }
                            } else if (realPosition >= mealCardIndxList.get(i - 1) && realPosition < mealCardIndxList.get(i)) {
                                if (indicator.getCurrentPosition() != i) {
                                    indicator.setCurrentItem(i);
                                    break;
                                }
                            }
                            //可能會有i==0的情況下屬于如下情況 所以不加else if
                            if (i == mealCardIndxList.size() - 1) {
                                if (realPosition >= mealCardIndxList.get(i)) {
                                    if (indicator.getCurrentPosition() != i + 1) {
                                        indicator.setCurrentItem(i + 1);
                                    }
                                }
                            }
                        }
                    }
                }
            }

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

                switch (newState) {
                    case RecyclerView.SCROLL_STATE_DRAGGING:
                        isFormTabScroll = false;
                        break;
                    case RecyclerView.SCROLL_STATE_IDLE:
                        if (flowDetailActivity != null && !flowDetailActivity.isCloseNps()) {

                            UIUtils.postDelayRunnable(new Runnable() {
                                @Override
                                public void run() {
                                    if (!flowDetailActivity.isShowNps()) {
                                        flowDetailActivity.showNPS();
                                    }
                                }
                            }, 100);
                        }
                        break;
                    default:
                        break;
                }
            }
        });

3.點擊tab位置RecycleView滑動到相應位置

通過RecycleView的scrollBy()scrollToPosition()兩個方法實現(xiàn)。為scrollToPosition()只會保證滑動的position出現(xiàn)在視野中,不會保證該position在頂端,所以需要通過scrollBy()完成置頂?shù)幕瑒印?/p>

    public void moveRecycleViewToPosition(int n) {
        isFormTabScroll = true;

        //先從RecyclerView的LayoutManager中獲取第一項和最后一項的Position
        int firstItem = layoutManager.findFirstVisibleItemPosition();
        int lastItem = layoutManager.findLastVisibleItemPosition();
        //然后區(qū)分情況
        if (n < firstItem) {
            //當要置頂?shù)捻椩诋斍帮@示的第一個項的前面時
            mRecyclerView.scrollToPosition(n);
            if (n != 0) {
                mIndex = n;
                needMoveToTop = true;
            }
        } else if (n <= lastItem) {
            //當要置頂?shù)捻椧呀?jīng)在屏幕上顯示時
            int top = mRecyclerView.getChildAt(n - firstItem).getTop();
            mRecyclerView.scrollBy(0, top);
        } else {
            //當要置頂?shù)捻椩诋斍帮@示的最后一項的后面時
            mRecyclerView.scrollToPosition(n);
            //這里這個變量是用在RecyclerView滾動監(jiān)聽里面的
            mIndex = n;
            needMoveToTop = true;
        }
    }

可以看到在該position不在屏幕中時,指定了一個字段needMoveToTop = true,因為需要在scrollToPosition()方法后再執(zhí)行scrollBy()完成置頂操作。這個標記是監(jiān)聽RecycleView滑動完成之后用來標識完成scrollBy()最后置頂滑動的,具體代碼如下:

        mRecyclerView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
            @Override
            public void onScrollChanged() {

                //將改item滑動到頂部
                if (needMoveToTop) {
                    needMoveToTop = false;
                    //獲取要置頂?shù)捻椩诋斍捌聊坏奈恢?,mIndex是記錄的要置頂項在RecyclerView中的位置
                    int n = mIndex - layoutManager.findFirstVisibleItemPosition();
                    if (0 <= n && n < mRecyclerView.getChildCount()) {
                        //獲取要置頂?shù)捻楉敳侩xRecyclerView頂部的距離
                        int top = mRecyclerView.getChildAt(n).getTop();
                        //最后的移動
                        mRecyclerView.scrollBy(0, top);
                    }
                }
            }
        });

總體實現(xiàn)難度并不大,至此就完成了滑動錨點定位的邏輯。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容