前言
首先和大家道个歉,实在是不好意思,距离上次博客过了很久才更新,由于新项目启动,朋友那边又要我帮他做个辅助,加上元旦放假,的确耽误了很久,现在基本项目工作进度稳定下来,我也要恢复进度,保持博客的稳定了。也不知道大家最近啥时候回家过年,时间也快到年底了,大家是不是都在等年终奖呢,然后回家发红包,哈哈。不过我最近还遇到点生活上麻烦的事情,嗨,感觉又要奔波,又要折腾一次了。
源码下载地址在最后!~
简介
先来看一下上次我们讲了什么,如果没有看过前面两篇博文的,可以先去阅读以下Android RecyclerView 梦幻般的控件 使用解析(一)、Android RecyclerView 梦幻般的控件 使用解析(二)。之前我们讲的东西也比较简单,就是基本如何使用RecyclerView和怎么添加分隔线,今天开始才是RecyclerView的魅力所在,让我们看看梦幻般的她吧~!
使用方法
先把上次留下来的问题再补充一下哈,我们要怎么自定义分隔线呢?大家也都知道了,我们自定义一个itemdecoration_bg.xml,然后这个东西就比较随性了,大家可以发挥各自的艺术细胞,当然我只有艺术细菌,也简单给大家写一个看看吧,如下:
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient
android:centerColor="#0000ff"
android:endColor="#00ff00"
android:startColor="#00ffff"
android:type="linear" />
<size android:height="2dp"
android:width="2dp"/>
<padding
android:left="5dp"
android:top="1dp"
android:right="5dp"/>
</shape>
基本上我的艺术细菌也就这么多了,大家可以根据具体需求去画,反正这个东西比较自由随意。OK那么我们继续,看来这么多,再加上前面的两篇博文,的确这个东西用起来好像也真的不简单,至少比以前的ListView要麻烦,好了,关键点来了,我们来看下一,我如果这个改一下呢?看代码
recyhclerView = (RecyclerView) findViewById(R.id.recycleView);
//recyhclerView.setLayoutManager(new LinearLayoutManager(this));
recyhclerView.setLayoutManager(new GridLayoutManager(this,4));
recyhclerView.setAdapter(new MyRecyclerAdapter());
是不是很神奇,对的,一下子将ListView效果变成了GridView,你想,比如你是商城类的一个APP,在ListView和GridView之间切换是不是超级容易,有木有啊。好了,接下来我们就来讲一下这个LayoutManager吧。
RecyclerView.LayoutManager看源码
public static abstract class LayoutManager {
ChildHelper mChildHelper;
RecyclerView mRecyclerView;
这是一个抽象类,好在系统提供了3个实现类:
LinearLayoutManager 现行管理器,支持横向、纵向。
GridLayoutManager 网格布局管理器
StaggeredGridLayoutManager 瀑布就式布局管理器
那么我们再来看一下后面那个瀑布式布局,改一下代码:
recyhclerView.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));
当然这样的写法实现效果和GridView是一样的,但是注意一下,StaggeredGridLayoutManager的第二个参数是Orientation,仔细看一下,我们刚才用的是VERTICAL,大家看意思就能明白了,接下来我们来试试
StaggeredGridLayoutManager.HORIZONTAL
recyhclerView.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.HORIZONTAL));
是不是很神奇,如果你需要一个横向的GridView,那么恭喜你,这个轻而易举就是可以实现。
当然,大家也发现了,我这个分隔线并不适用后面两种布局管理器,这里借鉴一下大神们的分隔线,如下:
DividerGridItemDecoration
package com.mic.blin.myrecyclerview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
/**
* Created by zhaocheng on 2016/1/14.
*/
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration
{
private static final int[] ATTRS = new int[] { android.R.attr.listDivider };
private Drawable mDivider;
public DividerGridItemDecoration(Context context)
{
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
}
@Override
public void onDraw(Canvas c, RecyclerView parent, State state)
{
drawHorizontal(c, parent);
drawVertical(c, parent);
}
private int getSpanCount(RecyclerView parent)
{
// 列数
int spanCount = -1;
LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager)
{
spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
} else if (layoutManager instanceof StaggeredGridLayoutManager)
{
spanCount = ((StaggeredGridLayoutManager) layoutManager)
.getSpanCount();
}
return spanCount;
}
public void drawHorizontal(Canvas c, RecyclerView parent)
{
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++)
{
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getLeft() - params.leftMargin;
final int right = child.getRight() + params.rightMargin
+ mDivider.getIntrinsicWidth();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawVertical(Canvas c, RecyclerView parent)
{
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++)
{
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getTop() - params.topMargin;
final int bottom = child.getBottom() + params.bottomMargin;
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicWidth();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private boolean isLastColum(RecyclerView parent, int pos, int spanCount,
int childCount)
{
LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager)
{
if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
{
return true;
}
} else if (layoutManager instanceof StaggeredGridLayoutManager)
{
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
if (orientation == StaggeredGridLayoutManager.VERTICAL)
{
if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
{
return true;
}
} else
{
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
return true;
}
}
return false;
}
private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,
int childCount)
{
LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager)
{
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
return true;
} else if (layoutManager instanceof StaggeredGridLayoutManager)
{
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
// StaggeredGridLayoutManager 且纵向滚动
if (orientation == StaggeredGridLayoutManager.VERTICAL)
{
childCount = childCount - childCount % spanCount;
// 如果是最后一行,则不需要绘制底部
if (pos >= childCount)
return true;
} else
// StaggeredGridLayoutManager 且横向滚动
{
// 如果是最后一行,则不需要绘制底部
if ((pos + 1) % spanCount == 0)
{
return true;
}
}
}
return false;
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition,
RecyclerView parent)
{
int spanCount = getSpanCount(parent);
int childCount = parent.getAdapter().getItemCount();
if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部
{
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
} else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边
{
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else
{
outRect.set(0, 0, mDivider.getIntrinsicWidth(),
mDivider.getIntrinsicHeight());
}
}
}
其实东西并不复杂,主要在getItemOffsets方法中,去判断是不是最后一行,如果是最后一行,则不需要绘制底部的分隔线了,如果是最后一列的话,那就不需要绘制右边的分隔线了,去理解一下就可以了,主要学习人家的思想,如何自己去绘制不重要。效果图:
我们继续看瀑布流布局,其实我们已经实现了,因为我们的高度是固定写死的,如果我们把高度设置成随机呢,我们来试试,我们在我们的适配器onBindViewHolder方法中来随机设置item的高度。
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();
lp.height = (int) (100 + Math.random() * 300);
holder.tv.setLayoutParams(lp);
holder.tv.setText(data.get(position));
}
有木有很容易啊,一下子就实现了瀑布流,毕竟写个瀑布流还是挺麻烦的。
总结
总的来说,RecyclerView这个控件还是非常好用的,也是非常人性化的,当然也是对以前的ListView和GridView等控件的一种整合吧,把更多的自由交给开发人员,简单用法很简单,当然如果要加入点击事件,滑动事件,触摸时间,下拉,上拉事件的话,答题思路和ListView肯定是差不多的,所以大家有兴趣也可以去自己尝试写一下,东西不难,但是好用。
PS
到这里,大家不知道还怎么看待这个控件,我是超级喜欢的,我觉得也不用多久,基于RecyclerView的第三方类似于RefreshListView的框架也会横空出世吧。基本上RecyclerView也就讲到这里了,毕竟生活在上海,现在各种繁琐的事情,今晚回家又有烦心事要处理,真的是像狗一样的生活。