天天看點

Recyclerview關聯翻頁

Recyclerview關聯翻頁

如上圖所示,要想實作此類效果,第一聯想到的就是viewpager了,因為它翻頁啊,然後處理它的關聯以及跟随翻頁時效果展示,但是我們今天研究的是用兩個Recyclerview去實作,有人就問了,這玩意不是清單麼,我咋翻頁啊,不會還要自己處理吧,别怕,了解的人都知道了谷歌有個PagerSnapHelper,完美貼合咱們的需求,完成翻頁效果,代碼大概如下:

PagerSnapHelper snapHelperContent=new PagerSnapHelper();
snapHelperContent.attachToRecyclerView(mRvContent);
           

ok,這樣就實作了翻頁效果,想要研究原理的,自行檢視源代碼,這裡不做重點講述。

接着我們簡單進行布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
      />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_top"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="@+id/rv_content"
        android:translationY="-70dp"
        />

</androidx.constraintlayout.widget.ConstraintLayout>
           

實作簡單的上下兩個清單的adapter資料填充後,大概效果如下:

Recyclerview關聯翻頁

要想實作理想中的效果,我們必須給清單添加分割線,這裡隻貼出下面清單的分割線代碼:

public class TopItemDecoration extends RecyclerView.ItemDecoration {
    private int mLeftMargin;

    public TopItemDecoration(Context context) {
            mLeftMargin = (Globals.SCREEN_WIDTH - ScreenUtils.dp2px(context,100)) / 2;
    }
    
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view);
        int itemCount = parent.getAdapter().getItemCount();
        int leftMargin;
        int rightMargin;
        if (position == 0) {
            leftMargin = mLeftMargin;
        } else {
            leftMargin = 0;
        }
        if (position == itemCount - 1) {
            rightMargin = mLeftMargin;
        } else {
            rightMargin = 0;
        }
        RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
        layoutParams.setMargins(leftMargin, 0, rightMargin, 0);
        super.getItemOffsets(outRect, view, parent, state);
    }
}

           

好了,我們再看下效果:

Recyclerview關聯翻頁

到這裡翻頁和大體布局已經完成了,下面就是核心的滑動過程處理了,以下舉例下面recyclerview的監聽:

@Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (mRvContent.getChildCount() == 1) {
                    View view = mRvContent.getChildAt(0);
                    view.setScaleY(1);
                    view.setScaleX(1);
                } else {
                    for (int i = 0; i < mRvContent.getChildCount(); i++) {
                        View view = mRvContent.getChildAt(i);
                        float rate;
                        int left = (view.getLeft() + view.getRight()) / 2;
                        if (left <= mGalleryMiddle) {
                            if (left < mGalleryMiddle - mGalleryMove) {
                                rate = 1f;
                            } else {
                                rate = (mGalleryMiddle - left) * 1f / mGalleryMove;

                            }
                            view.setScaleY(1 - rate * mGalleryScaleY);
                            view.setScaleX(1 - rate * mGalleryScaleY);
                            view.setTranslationX(rate * mGalleryTranslation);
                        } else {
                            if (left > mGalleryMiddle + mGalleryMove) {
                                rate = 0f;
                            } else {
                                rate = (mGalleryMiddle + mGalleryMove - left) * 1f / mGalleryMove;
                            }
                            view.setScaleY((1 - mGalleryScaleY) + rate * mGalleryScaleY);
                            view.setScaleX((1 - mGalleryScaleY) + rate * mGalleryScaleY);
                            view.setTranslationX((rate - 1) * mGalleryTranslation);
                        }
                    }
                }
            }
           

同理也可實作頂部清單的滾動變化,難度不大,詳見源碼。

重點是兩個清單如何進行關聯呢,肯定在下面清單滾動監聽過程中,去觸發上面清單的滾動,但是上下布局不一樣大,是以我們要等比例進行滾動:

乍一看沒啥問題,我們跑下代碼試試,恩,感覺有那個意思了,不對啊,咋感覺怪怪的,為啥越往後滑,錯位越大,不在正中央,這就尴尬了,而且當你緩慢滑動下面清單時,上面清單壓根就不叼你。

Recyclerview關聯翻頁
這是因為public void scrollBy(int x, int y) 這個方法的參數隻能傳int值

這就導緻了精度的丢失,那我們換scrooTo吧,直接一步到位,不就沒有什麼誤差了麼,

然而請看recyclerview中:

@Override
    public void scrollTo(int x, int y) {
        Log.w(TAG, "RecyclerView does not support scrolling to an absolute position. "
                + "Use scrollToPosition instead");
    }
           

這tm~,不好意思,沒忍住,這還咋玩啊,既然recyclerview沒有給我們實作,那我們就換個思路,自己去完成“一步到位”的滾動吧。

我們回看

mRvTop.scrollBy(dx * 100 / 327, dy);

這段代碼,此處dx是下面清單每次滑動的距離,然後換算比例得出上面清單需要疊加滑動距離,然後調用scrollBy方法,但是這樣誤差會一直疊加,是以我們換種思路,下面的清單我們每次拿到總滑動距離,然後換算比例得出上面清單需要滑動的總距離,然後再減去上面清單目前滑動距離,得出來的資料不就是沒有誤差的滑動差麼,這樣我們就可以正大光明調用scrollBy方法了:

mTotalContentX += dx;
mRvTop.scrollBy(mTotalContentX * 100 / 327 - mTotalTopX, dy);
           

大功告成,我們看下最終實作效果:

Recyclerview關聯翻頁

源碼下載下傳