使用RecycleView打造水平分页GridView

2017-01-14 10:04:36来源:http://www.jianshu.com/p/262f4b632a41作者:zhuguohui人点击

效果

效果
特点

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


使用
1.在布局文件中定义

这里写图片描述

支持的属性如下



这里写图片描述
2.设置Adapter
  //设置adapter
pageGridView.setAdapter(adapter1);
//设置点击监听器
pageGridView.setOnItemClickListener(adapter1);
//设置分页指示器
pageGridView2.setPageIndicator(pageIndicator);

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


下面是各个借口的定义


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



这里写图片描述

点击监听器



这里写图片描述

分页指示器



这里写图片描述
实现
遇到的问题

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



这里写图片描述

对比分页的样式



这里写图片描述

发下有下列问题:


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


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


1.重排序

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



这里写图片描述

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



这里写图片描述

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



这里写图片描述
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地址




最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台