RecycleView实现网格整页滑动

需求分析

这篇博客写作来源是项目需求
产品经理说:用六宫格展示一页数据,用户左滑/右滑的时候,要整页滑动的效果。
解释这句话的意思就是:
(1)一页只能展示6条数据;
(2)只支持横向滑动,用户只能一页一页的滑(相当于用户一次要滑动6条数据);
(3)用户左滑是向前翻页,右上角页码随之变换;
(4)用户右滑是向后翻页,右上角页码随之变换;
(5)点击单条数据,可以跳转这道菜的详情页面。
以下是产品原型图:
RecycleView实现网格整页滑动_第1张图片
我在github上逛了挺久的,就是找不到贴合我们实际项目需求的控件。我认为这个功能类似于下拉刷新和上拉加载更多,所不同的是,首先,这个不是垂直方向的,其次,滑动的话只能按照页面滑,一次变更6条数据。
既然如此,只好自己动手动脑来实现了。
我的想法其实很简单粗暴,就是自己监听用户是向左滑还是右滑还是在点击item,之后做不同的滑动和点击事件处理。这个方法一开始没有想到,试了其他方案都不成功,最后被逼出的这个。这也说明,项目需求有时候不会一眼就做出来的时候,多试试其他方案,试的过程中,想法也就出来了。

实现:

采用recycleview + gridlayoutmanager,在recycleview中监听用户的触摸事件,核心代码如下:
注意:当用户滑动的时候,我们自己处理此事件;但是如果是用户点击item的话,就继续交回给父控件自己处理,因为recycleview本身就是支持点击事件的,所以之前返回什么值,就返回什么值,不做改变就好。
但是遗留了一个问题:就是滑动之后,再点击,第一次不响应这个点击,之后开始响应点击事件了。
希望能有人帮忙解答。

   public class MyRecycleView extends RecyclerView {
    private long startTime;
    private float mTouchStartX;
    private int pressX;
    public static final String TAG = "MyRecycleView";

    private MyScrollListener mMyScrollListener;

    public void setMyScrollListener(MyScrollListener myScrollListener) {
        mMyScrollListener = myScrollListener;
    }

    public MyRecycleView(@NonNull Context context) {
        super(context);
    }

    public MyRecycleView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyRecycleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                startTime = System.currentTimeMillis();
                mTouchStartX = event.getX();
                pressX = (int) event.getRawX();
                Log.d(TAG,"mTouchStartX = "+mTouchStartX);
                Log.d(TAG,"pressX = "+pressX);
               break;
            case MotionEvent.ACTION_MOVE:
                float mMoveStartX = event.getX();
                int deltaX = (int) (mMoveStartX - mTouchStartX);
                Log.d(TAG,"deltaX = "+deltaX);
                break;
            case MotionEvent.ACTION_UP:
                int tempDX = (int) event.getRawX() - pressX;
                mTouchStartX = event.getX();
                Log.d(TAG,"tempDX = "+tempDX);
                if(tempDX<=6&&tempDX>=-6){
                    long endTime = System.currentTimeMillis();
                    if ((endTime - startTime) < 2 * 1000L) {
                        //设置点击事件:
                        Log.d(TAG,"点击事件 ");
                        return super.onTouchEvent(event);
                    }
                }else if(tempDX>6){//6这个值没有什么实际意义,只是认为差不多这个值就可以做滑动和点击的区分
                    if(mMyScrollListener!=null){
                        Log.d(TAG,"onRefresh ");
                        mMyScrollListener.onRefresh();
                    }
                }else if(tempDX<-6){
                    if(mMyScrollListener!=null){
                        Log.d(TAG,"onLoadMore ");
                        mMyScrollListener.onLoadMore();
                    }
                }
             break;
        }
        return true;

    }

    public interface MyScrollListener {
        void onLoadMore();
        void onRefresh();
    }

}

使用:

和原本recycleview的使用保持不变,只不过要实现自己定义的两个接口:

rvRecipe.setMyScrollListener(this);//加载之后/之前页面数据
mRecipeListAdapter.setOnItemClickListener(this);//点击事件


 @Override
    public void onLoadMore() {
        Log.d(TAG,"加载更多");
        mPresenter.fetchRecipesData();
    }

    @Override
    public void onRefresh() {
        Log.d(TAG,"获取之前页面的数据");
        mPresenter.fetchPreviousRecipesData();
    }

其实还有一个问题:就是采用这样的方案,用户滑动的时候,虽然用户能感知到一次性6条数据做了变更,这给人感觉好像页面整体都滑动了,但实际上这个控件是没有任何滑动效果的。

最终效果图就是这个样子了:
RecycleView实现网格整页滑动_第2张图片

你可能感兴趣的:(Android控件)