本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发。
RecyclerView的时代
自从google推出了RecyclerView
这个控件, 铺天盖地的一顿叫好, 开发者们也都逐渐从ListView
,GridView
等控件上转移到了RecyclerView
上, 那为什么RecyclerView
这么受开发者的青睐呢? 一个主要的原因它的高灵活性, 我们可以自定义点击事件, 随意切换显示方式, 自定义item动画, 甚至连它的布局方式我们都可以自定义.
吐吐嘈
夸完了RecyclerView
, 我们再来吐槽一下大家在工作中各种奇葩需求, 大家在日常工作中肯定会遇到各种各种的奇葩需求, 这里没就包括奇形怪状的需求的UI. 站在我们开发者的角度, 看到这些奇葩的UI, 心中无数只草泥马呼啸崩腾而过, 在愤愤不平的同时还不得不老老实实的去找解决方案… 好吧, 吐槽这么多, 其实大家都没有错, 站在开发者的角度, 这样的需求无疑增加了我们很多工作量, 不加班怎么能完成? 但是站在老板的角度, 他也是希望将产品做好, 所以才会不断的思考改需求.
效果展示
开始进入正题, 今天我们的主要目的还是来自定义一个LayoutManager
, 实现一个奇葩的UI, 这样的一个布局我也是从我的一个同学的需求那看到的, 我们先来看看效果.
当然了, 效果不是很优雅, 主要是配色问题, 配色都是随机的, 所以肯定没有UI上好看. 原始需求是一个死的布局, 当然用自定义View的形式可以完成, 但是我认为那样不利于扩展, 例如效果图上的从每组3个变成每组9个, 还有一点很重要, 就是用RecyclerView
我们还得轻松的利用View
的复用机制. 好了, UI我们就先介绍到这, 下面我们开始一步步的实现这个效果.
自定义LayoutManager
前面说了, 我们这个效果是利用自定义RecyclerView
的LayoutManager
实现的, 所以, 首先我们要准备一个类让它继承RecyclerView.LayoutManager
.
public class CardLayoutManager extends RecyclerView.LayoutManager {
}
定义完成后, android studio会提醒我们去实现一下RecyclerView.LayoutManager
里的一个抽象方法,
public class CardLayoutManager extends RecyclerView.LayoutManager {
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
这样, 其实一个最简单的LayoutManager
我们就完成了, 不过现在在界面上是什么也没有的, 因为我们还没有对item view进行布局. 在开始布局之前, 还有几个参数需要我们从构造传递, 一个是每组需要显示几个, 一个当每组的总宽度小于RecyclerView
总宽度的时候是否要居中显示, 来重写一下构造方法.
public class CardLayoutManager extends RecyclerView.LayoutManager {
public static final int DEFAULT_GROUP_SIZE = 5;
// ...
public CardLayoutManager(boolean center) {
this(DEFAULT_GROUP_SIZE, center);
}
public CardLayoutManager(int groupSize, boolean center) {
mGroupSize = groupSize;
isGravityCenter = center;
mItemFrames = new Pool<>(new Pool.New<Rect>() {
@Override
public Rect get() { return new Rect();}
});
}
// ...
}
ok, 在完成准备工作后, 我们就开始着手准备进行item的布局操作了, 在RecyclerView.LayoutManager
中布局的入口是一个叫onLayoutChildren
的方法. 我们来重写这个方法.
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getItemCount() <= 0 || state.isPreLayout()) { return;}
d