使用RecycleView打造水平分页GridView

效果

特点

1.支持纵向,横向,水平分页三种布局方式。
2.支持点击事件。
3.支持分割线设置,支持自定义分页指示器。
4.使用简单方便

使用

1.在布局文件中定义

使用RecycleView打造水平分页GridView_第1张图片

支持的属性如下

使用RecycleView打造水平分页GridView_第2张图片

2.设置Adapter

  //设置adapter
  pageGridView.setAdapter(adapter1);
  //设置点击监听器
  pageGridView.setOnItemClickListener(adapter1);
  //设置分页指示器
   pageGridView2.setPageIndicator(pageIndicator);

注意
如果使用分页显示,由于会对数据进行重排序,所以点击事件的position只用和数据集合结合使用。

下面是各个借口的定义

使用分页功能必须使用此Adapter

使用RecycleView打造水平分页GridView_第3张图片

点击监听器

使用RecycleView打造水平分页GridView_第4张图片

分页指示器
使用RecycleView打造水平分页GridView_第5张图片

实现

遇到的问题

其实打造分页的GridView可以使用多种方式,比如常见的用GridView加ViewPager实现,但是这种方式没有实现对View的复用,而且编码复杂,光是对Adapter的处理就很头疼,所以我将这些辛苦的工作我都做了,辛苦我一个方便大家。我的思路是使用RecycleView结合StaggeredGridLayoutManager来实现分页,但是在默认的效果中只能实现如下效果。

使用RecycleView打造水平分页GridView_第6张图片

对比分页的样式

使用RecycleView打造水平分页GridView_第7张图片

发下有下列问题:

1.数据排列,分页的数据是一页页,一行行的排。

2.滑动事件的处理,分页的数据应该是一页一页显示,当滑动停止的时候自动停在最近一页。

1.重排序

下面我一个一个的解决这些问题,首先是数据排列。我通过以下算法对数据就行了重排序。

使用RecycleView打造水平分页GridView_第8张图片

关键的逻辑是获取到Adapter的数据,并对它安装分页的方式进行重排序,对于一些位置采用了空数据处理。所以为了实现这些功能,使用者的Adapter必须实现PagingAdapter

使用RecycleView打造水平分页GridView_第9张图片

而且必须对空对象进行处理

使用RecycleView打造水平分页GridView_第10张图片

2.滑动事件

由于RecycleView自己并不处理滑动事件,而是委派给LayoutManager处理,所以通过RecycleView的getScrollX方法不能获取到滑动的偏移量,而且使用smoothScrollToPosition()方法有一个问题,就是当指定Position的view已经在视线内的时候,是不会滑动的。因此经过我反复的实验采用以下的方法解决了问题。即通过给RecycleView设置OnScrollListener实现。

  int scrollX = 0;
    boolean isAuto = false;
    int Target = 0;
    int currentPage = 0;
    int lastPage = 0;

    public class PagingScrollListener extends RecyclerView.OnScrollListener {


        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

            if (newState == 0) {
                if (!isAuto) {
                    int p = scrollX / getWidth();
                    int offset = scrollX % getWidth();
                    if (offset > getWidth() / 2) {
                        p++;
                    }
                    Target = p * getWidth();
                    isAuto = true;
                    currentPage = p;
                    if (pageIndicator != null) {
                        pageIndicator.onPageUnSelected(lastPage);
                        pageIndicator.onPageSelected(currentPage);
                    }
                    if (onPageChangeListenerList != null) {
                        for (OnPageChangeListener listener : onPageChangeListenerList) {
                            listener.onPageChanged(currentPage);
                        }
                    }
                    recyclerView.smoothScrollBy(Target - scrollX, 0);
                }
            } else if (newState == 2) {
                isAuto = false;
                lastPage = currentPage;
            }

        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            scrollX += dx;

        }

    }

3.点击事件的处理

我通过重写dispatchTouchEvent方法实现

   @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (onItemClickListener != null) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    dX = (int) ev.getRawX();
                    dY = (int) ev.getRawY();
                    dTime = System.currentTimeMillis();

                    break;
                case MotionEvent.ACTION_UP:
                    int mx = (int) Math.abs(ev.getRawX() - dX);
                    int my = (int) Math.abs(ev.getRawY() - dY);
                    int time = (int) (System.currentTimeMillis() - dTime);
                    if (mx <= 10 && my <= 10 && time < 200) {
                        int position = getPositionByXY((int) ev.getRawX(), (int) ev.getRawY());
                        if (position != -1) {
                            onItemClickListener.onItemClick(this, position);
                        }
                    }
                    break;
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    private int getPositionByXY(int x, int y) {
        int position = -1;
        Rect rect = new Rect();
        for (int i = 0; i < getChildCount(); i++) {
            View view = getChildAt(i);
            view.getGlobalVisibleRect(rect);
            if (rect.contains(x, y)) {
                position = i;
                break;
            }
        }
        if (mRows > 0) {
            int offset = getChildPosition(getLayoutManager().getChildAt(0));
            position += offset;
        }
        return position;
    }

    private OnItemClickListener onItemClickListener;

    public void setOnItemClickListener(OnItemClickListener listener) {
        onItemClickListener = listener;
    }

关于更多的细节请查看源码。

GitHub

github地址

你可能感兴趣的:(Android)