1. 程式人生 > 其它 >使用 RecyclerView 實現 Gallery 畫廊效果,並控制 Item 停留位置

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

RecyclerView 作為一個列表滑動控制元件,我們都知道它既可以橫向滑動,也可以豎直滑動,可以實現線性佈局管理,瀑布流佈局管理,還有 GridView 佈局管理。其實我們可以控制其 Item 的停留位置,並使其實現畫廊效果。如果大家熟悉 SnapHelper 的話,估計大家就都會了。

什麼是 SnapHelper

SnapHelper 的實現原理就是是監聽 RecyclerView.OnFlingListener 中的 onFling 介面。support library 中只提供了一個繼承類 LinearSnapHelper ,LinearSnapHelper 是抽象類 SnapHelper 的具體實現。 通過 LinearSnapHelper,我們就可以使 RecyclerView 實現類似 ViewPager 的功能,無論怎麼滑動最終都會停留在列表頁面正中間。

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

效果如下:

居中實現方式

使用 SnapHelper 配合 RecyclerView 實現控制 Item 位置居中顯示,非常簡單,官方預設提供的 LinearSnapHelper 就是居中的,我們直接使用即可。

程式碼如下:

  1. LinearLayoutManager linearLayoutManager = new
  2. LinearLayoutManager(this,
  3. LinearLayoutManager.HORIZONTAL,
    false);
  4. recyclerView.setLayoutManager(linearLayoutManager);
  5. new LinearSnapHelper().
  6. attachToRecyclerView(recyclerView);

自定義 SnapHelper

官方提供的預設是居中顯示,其實我們也可以自定義,比如:靠左顯示,讓可見的第一個 Item 居左顯示。

效果圖如下

自定義 SnapHelper ,一般需要實現兩個方法:

  • 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:

  1. CustomSnapHelper mMySnapHelper = new CustomSnapHelper();
  2. mMySnapHelper.attachToRecyclerView(rv);

最後,其實垂直方向也可以實現哦,大家可以嘗試一下垂直方向的使用方式是不是非常簡單。

程式碼 Demo 地址:https://github.com/loonggg/SnapHelperDemo