1. 程式人生 > >recyclerview 實現viewpager grideview分頁效果 GrideSnapHelper

recyclerview 實現viewpager grideview分頁效果 GrideSnapHelper

為了逼自己學習,所以瞎折騰一下,讓自己張點見識。

專案中原來使用的是ViewPager + GrideView 實現的卡片滑動,程式碼挺多的,我非得想改造成用recyclerView實現,

話說折騰成功。先看下效果。


每頁三列,滑動停止後自動找到最近的一頁停下。

大多數人都是直接實現SnapHelper,但是我武功沒那麼高強,況且只要能解決問題的同志就是好裁縫!對於那些沒有問題製造困難也要解決問題的好同志,我只能說,帶我飛.

我給這個類起名叫GrideSnapHelper,感覺實現了GrideSnapHelper很高達上...其實我只實現了滾動監聽而已.

使用方法:

        GrideSnapHelper grideSnapHelper = new GrideSnapHelper(3,3,this);
        grideSnapHelper.attachToRecycleView(recyclerView);

GrideSnapHelper原始碼

    import android.app.Activity;
        import android.support.v7.widget.GridLayoutManager;
        import android.support.v7.widget.RecyclerView;
        import android.util.Log;
        import android.view.View;
        import android.view.WindowManager;

        import java.util.ArrayList;

        import static android.content.ContentValues.TAG;
        import static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING;
        import static android.support.v7.widget.RecyclerView.SCROLL_STATE_SETTLING;
        import static android.widget.NumberPicker.OnScrollListener.SCROLL_STATE_IDLE;

/**
 * Created by 瑜哥 on 2018/3/29.
 * 1:尋找錨點:visiable fist last範圍內%行*列=0的都是錨點
 * 2:錨點為正,如果超過螢幕的一半,取當前錨點-1,如果小於螢幕一半取當前錨點
 */

public class GrideSnapHelper {

    RecyclerView recyclerView;
    int horizon, column;
    private GridLayoutManager layoutManager;
    private ArrayList<Integer> positionLisit;
    private final int screen_width;

    public GrideSnapHelper(int horizon, int column, Activity ctx) {
        this.horizon = horizon;
        this.column = column;
        WindowManager wm1 = ctx.getWindowManager();
        screen_width = wm1.getDefaultDisplay().getWidth();
    }

    public void attachToRecycleView(RecyclerView recyclerView) {
        this.recyclerView = recyclerView;
        setListener();
    }

    private void setListener() {
        if (recyclerView == null) {
            return;
        }
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                switch (newState) {
                    case SCROLL_STATE_IDLE:
                        System.out.println("recyclerview已經停止滾動");
                        snapView();
                        break;
                    case SCROLL_STATE_DRAGGING:
                        System.out.println("recyclerview正在被拖拽");
                        break;
                    case SCROLL_STATE_SETTLING:
                        System.out.println("recyclerview正在依靠慣性滾動");
                        break;
                }
            }
        });


    }

    private void snapView() {
        if (layoutManager ==null) {
            layoutManager = (GridLayoutManager)recyclerView.getLayoutManager();
            positionLisit = new ArrayList<>();
        }
        //尋找錨點
        positionLisit.clear();
        int firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
        int lastVisibleItem = layoutManager.findLastVisibleItemPosition();
        for (int i = firstVisibleItem;i<=lastVisibleItem;i++) {
            if (i%(column*horizon)==0)
                positionLisit.add(i);
        }
        Log.d(TAG, "positionLisit: "+positionLisit.toString());
        //選擇錨點
        int targetPosition = 0;
        //有1個錨點  錨點X座標大於螢幕一半取上一個錨點,錨點X座標小於螢幕一半取當前錨點
        if (positionLisit.size() == 1) {
            View item = layoutManager.findViewByPosition(positionLisit.get(0));
            if (item==null) return;
            final int []location=new int[2];
            item.getLocationOnScreen(location);
            int x=location[0];//獲取當前位置的橫座標
            int y=location[1];//獲取當前位置的縱座標
            if (x > screen_width / 2) {
                targetPosition = positionLisit.get(0) - column * horizon;
            } else {
                targetPosition = positionLisit.get(0);
            }
        }
        //有2個錨點  取小錨點
        else if (positionLisit.size() == 2) {
            targetPosition = positionLisit.get(0);
        }
        Log.d(TAG, "targetPosition: "+targetPosition);
//        recyclerView.smoothScrollToPosition(targetPosition);
        layoutManager.scrollToPositionWithOffset(targetPosition, 0);
    }
}

其實程式碼碼只有兩句話:

 1:尋找錨點:可視範圍內所有條目的Position%(每頁條目數)=0的都是錨點  
 2:選擇錨點:有1個錨點  錨點X座標大於螢幕一半取上一個錨點(當前錨點-每頁條目數),錨點X座標小於螢幕一半取當前錨點
                       有2個錨點  取position小的錨點