使用 RecyclerView 實現 Gallery 畫廊效果,並控制 Item 停留位置

RecyclerView 做爲一個列表滑動控件,咱們都知道它既能夠橫向滑動,也能夠豎直滑動,能夠實現線性佈局管理,瀑布流佈局管理,還有 GridView 佈局管理。其實咱們能夠控制其 Item 的停留位置,並使其實現畫廊效果。若是你們熟悉 SnapHelper 的話,估計你們就都會了。javascript

什麼是 SnapHelper

SnapHelper 的實現原理就是是監聽 RecyclerView.OnFlingListener 中的 onFling 接口。support library 中只提供了一個繼承類 LinearSnapHelper ,LinearSnapHelper 是抽象類 SnapHelper 的具體實現。
經過 LinearSnapHelper,咱們就能夠使 RecyclerView 實現相似 ViewPager 的功能,不管怎麼滑動最終都會停留在列表頁面正中間。 java

SnapHelper 和 ViewPager 的區別就是 ViewPager 一次只能滑動一頁,而 RecyclerView + SnapHelper 的方式能夠實現一次滑動好幾頁。android

效果以下:
git

居中實現方式

使用 SnapHelper 配合 RecyclerView 實現控制 Item 位置居中顯示,很是簡單,官方默認提供的 LinearSnapHelper 就是居中的,咱們直接使用便可。程序員

代碼以下:github

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(linearLayoutManager);
new LinearSnapHelper().attachToRecyclerView(recyclerView);複製代碼

自定義 SnapHelper

官方提供的默認是居中顯示,其實咱們也能夠自定義,好比:靠左顯示,讓可見的第一個 Item 居左顯示。微信

效果圖以下

自定義 SnapHelper ,通常須要實現兩個方法:ide

  • int[] calculateDistanceToFinalSnap(RecyclerView.LayoutManager layoutManager, View targetView) 當拖拽或滑動結束時會回調該方法,返回一個out = int[2],out[0]x軸,out[1] y軸,這就是咱們須要修改的位置偏移量
  • View findSnapView(RecyclerView.LayoutManager layoutManager) 該方法返回上面方法中須要的 targetView 。

代碼以下

public class CustomSnapHelper extends LinearSnapHelper {
    private OrientationHelper mHorizontalHelper;

    @Override
    public int[] calculateDistanceToFinalSnap(RecyclerView.LayoutManager layoutManager, View targetView) {
        int[] out = new int[2];
        //判斷支持水平滾動,修改水平方向的位置,是修改的out[0]的值
        if (layoutManager.canScrollHorizontally()) {
            out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager));
        } else {
            out[0] = 0;
        }
        return out;
    }

    private int distanceToStart(View targetView, OrientationHelper helper) {
        return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
    }

    @Override
    public View findSnapView(RecyclerView.LayoutManager layoutManager) {
        return findStartView(layoutManager, getHorizontalHelper(layoutManager));
    }

    private View findStartView(RecyclerView.LayoutManager layoutManager,
                               OrientationHelper helper) {

        if (layoutManager instanceof LinearLayoutManager) {
            int firstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
            int lastChild = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
            if (firstChild == RecyclerView.NO_POSITION) {
                return null;
            }
            //這行的做用是若是是最後一個,翻到最後一條,解決顯示不全的問題
            if (lastChild == layoutManager.getItemCount() - 1) {
                return layoutManager.findViewByPosition(lastChild);
            }

            View child = layoutManager.findViewByPosition(firstChild);
            //獲取偏左顯示的Item
            if (helper.getDecoratedEnd(child) >= helper.getDecoratedMeasurement(child) / 2
                    && helper.getDecoratedEnd(child) > 0) {
                return child;
            } else {
                return layoutManager.findViewByPosition(firstChild + 1);
            }
        }

        return super.findSnapView(layoutManager);
    }


    private OrientationHelper getHorizontalHelper(
            RecyclerView.LayoutManager layoutManager) {
        if (mHorizontalHelper == null) {
            mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
        }
        return mHorizontalHelper;
    }
}複製代碼

調用自定義的 SnapHelper 代碼以下,配合 RecyclerView:佈局

CustomSnapHelper mMySnapHelper = new CustomSnapHelper();
mMySnapHelper.attachToRecyclerView(rv);複製代碼

最後,其實垂直方向也能夠實現哦,你們能夠嘗試一下垂直方向的使用方式是否是很是簡單。this

代碼 Demo 地址:github.com/loonggg/Sna…

歡迎你們關注個人技術分享公衆號:非著名程序員(smart_android)。技術文章均先首發於個人技術分享的微信公衆號。

相關文章
相關標籤/搜索