MultiType-Adapter 优雅的实现RecyclerVIew中的复杂布局

MultiType-Adapter

一款轻量级支持多数据类型的 RecyclerView 适配器; 使用简单,完全解耦;
这么说吧:通讯聊天界面、朋友圈布局、淘宝 UI等复杂页面 优雅快速实现,无论你是一种数据有多种VIew类型,还是多种数据多种类型,还是两者都有,统统帮你快速地、优雅地搞定!
代码传送门

·总览
·特性
  · 基础用法
  · 单数据
  · 多数据-多类型
  · 单类型-多数据
  · 事件
·高级用法
  · 网格布局与线性布局混合编排
  · 瀑布流布局
  · 上拉加载
  · 无数据时过度界面设置
  · 混合布局拖拽实现
  · 悬浮吸顶效果
  · 设置复用数量
·扩展
·Thrank
`一些说明

总览

总体来讲支持以下效果

总览

特性

· 轻盈、整个类库只有9个文件
  · 全面、支持 bean type 之间 一对一 和 一对多 的关系绑定
  · 职责单一、只负责本分工作,专注多类型的列表视图 类型分发,不会影响 view 的内容或行为
  · 内存、没有性能损失,内存友好
  · 可读、代码清晰干净

基础用法

// root build.gradle
repositories {
    jcenter()
    maven { url "https://www.jitpack.io" }
}
// yout project build.gradle
dependencies {
        compile 'com.github.LidongWen:MultiTypeAdapter:0.2.6'
}

单数据

CommonAdapter adapter = new CommonAdapter<ItemClass>(this, ItemClass.class, R.layout.item_one) {
    @Override
    protected void convert(ViewHolder holder, final ItemClass item, int position) {
        holder.setText(R.id.tv_item01, item.name);
    }
};
....
recyclerView.setAdapter(adapter);

示例查看:single example

多数据-多类型

一个数据类型对应一种viewType

创建一个或多个 class 继承MultiItemView,这边做某一种数据类型 对应的 ItemView的创建,与数据装配

public class ItemVIew01 extends MultiItemView<Bean01> {
    @NonNull
    @Override
    public int getLayoutId() {
        return R.layout.item_one;
    }
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, @NonNull Bean01 item, int position) {
        holder.setText(R.id.tv_item01,item.title);
    }
}
public class Item ...

创建一个 适配器MultiTypeAdapter ,注册 beanMultiItemView 将适配器设入RecyclerView;

private MultiTypeAdapter adapter = new MultiTypeAdapter();
adapter.register(Bean01.class, new ItemVIew01());
adapter.register(Bean02.class, new ItemVIew02());
adapter.register(Bean03.class, new ItemVIew03());
...
adapter.setItems(items);
recyclerView.setAdapter(adapter);

示例查看:many2many Example

单数据-多类型

一种数据类型可以有多种ViewType

创建一个或多个 class 继承MultiItemView,其中 他们的数据类型要一致,重写 isForViewType方法

public class ItemVIew04 extends MultiItemView<Bean04> {
        ...
    @Override
    public boolean isForViewType(Bean04 item, int postion) {
        if (Bean04.TYPE_ONE.equals(item.type)) {
            return true;
        }
        return false;
    }
}

public class ItemVIew05 extends MultiItemView<Bean04> {
        ...
    @Override
    public boolean isForViewType(Bean04 item, int postion) {
        if (Bean04.TYPE_TWO.equals(item.type)) {
            return true;
        }
        return false;
    }
}

创建一个入口 class 继承MultiItemView , 构造函数时调用 addChildeItemView方法

public class ItemVIew06 extends MultiItemView<Bean04> {
    public ItemVIew06() {
        super();
        addChildeItemView(new ItemVIew04());
        addChildeItemView(new ItemVIew05());
        addChildeItemView(new ItemVIew07());
    }
}

activity

       adapter = new MultiTypeAdapter();
       adapter.register(Bean04.class, new ItemVIew06());
       ...

示例查看:one-many Example

事件

设置点击事件于长按事件

       adapter.setOnItemClickListener(new OnItemClickListener<ItemClass>() {
            @Override
            public void onItemClick(View view, RecyclerView.ViewHolder holder, ItemClass itemClass, int position) {
            }

            @Override
            public boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, ItemClass itemClass, int position) {
                return false;
            }
        });

高级用法

网格布局与线性布局混合编排

根据数据类型设置 view 比重

    adapter.register(String.class, new ItemVIewNormal()); // 一对一
    adapter.register(Bean01.class, new ItemVIew01());
    adapter.register(Bean02.class, new ItemVIew02());
    adapter.register(Bean03.class, new ItemVIew03());
    adapter.register(Bean04.class, new ItemVIew06());   // 一对多

         final GridLayoutManager layoutManager = new GridLayoutManager(this, SPAN_COUNT);
        GridLayoutManager.SpanSizeLookup spanSizeLookup = new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                Object item = items.get(position);
                if (item instanceof Bean01) {
                    return 1;
                }
                if (item instanceof Bean02) {
                    return 2;
                }
                if (item instanceof Bean03) {
                    return SPAN_COUNT;
                }
                if (item instanceof Bean04 ) {
                    return SPAN_COUNT;
                }
                if (item instanceof String) {
                    return SPAN_COUNT;
                }
                return 2;
            }
        };

示例查看:mix Example

瀑布流布局

示例查看:WaterFall Example

上拉加载

效果如下

loading.gif

将我们的 初始化LoadMoreWrapper2,添加上拉UI

    LoadMoreWrapper2 loadMoreWrapper2;
    private MultiTypeAdapter adapter;
    
    loadMoreWrapper2 = new LoadMoreWrapper2(adapter);
    loadMoreWrapper2.setLoadMoreView(LayoutInflater.from(this).inflate(R.layout.default_loading, recyclerView, false));
    recyclerView.setAdapter(loadMoreWrapper2);
    
    loadMoreWrapper2.setOnLoadMoreListener(new LoadMoreWrapper2.OnLoadMoreListener() {
        @Override
        public void onLoadMoreRequested() {
            loadMoreWrapper2.loadingComplete();//加载完毕
        }
    });
    
    // loadMoreWrapper2.setLoadMore(false); 开启或关闭加载功能

示例查看:pull-load Example

无数据时过度界面设置

    EmptyWrapper emptyWrapper;
    private MultiTypeAdapter adapter;
    
    emptyWrapper = new EmptyWrapper(adapter);
    emptyWrapper.setEmptyView(R.layout.layout_empty);
    recyclerView.setAdapter(emptyWrapper);

示例查看:Empty Example

混合布局拖拽实现

混合布局拖拽实现

吸顶效果

快速打造RecyclerView悬浮吸顶效果
一共有四种模式 请具体查看文章

sticky.gif

设置复用数量

业务需要,设置每种view的最大复用数量

public class ItemVIew01 extends MultiItemView<Bean01> {

    public void getMaxRecycleCount(){
        return 5;
    }
}

扩展

SasukeRecyclerView:基于MultiType-Adapter开发的一框下拉刷新上拉加载的库

Thrank

  • 鸿洋: 空白页功能与上拉加载功能 我拿过来稍微做了修改
  • Glide: 图片加载
  • drakeet学习其中的思想

一些说明

大家可能咋一看,会认为我抄袭 drakeet的代码,我虽然有学习过他的代码,其中也让我受益良多,不论是技术点还是架构松耦合方面的知识,但是,这份开源库虽然使用上与之相似,但完全手写,不存在抄袭 drakeet , 而且 是否抄袭 请大家阅读完源码之后再做评论,谢谢。

V 0.2.6  ·增加黏贴布局类型
V 0.2.5  ·GroupWrapper支持放入其他包中
V 0.2.0  ·分组伸展收缩功能
V 0.1.4
 ·悬浮吸顶效果增强:可随意搭配itemVIew为悬浮布局
 ·事件处理优化
V 0.1.3
 ·检测并修复切换悬浮头部状态时发生内存泄漏;

检测内存泄漏-内存占用图

V 0.1.2
 ·支持悬浮头部触摸事件,点击事件,长按事件等
 ·multiTypeAdapter支持restful风格调用
V 0.1.1
 ·MultiItemView 改变,更加简洁、直观
 ·新增 悬浮吸顶头部功能 快速打造Recyclerview悬浮吸顶头部


V 0.1.1
 ·支持头部吸顶功能
V 0.0.1
 ·实现一对一关系功能
 ·实现一对多关系功能
 ·事件监听
 ·支持网格、瀑布流、线性布局
 ·上拉加载功能
 ·数据为空时过渡界面展示功能

代码传送门:戳我!!!

来上一张架构图


multiTypeAdapter

希望我的文章不会误导在观看的你,如果有异议的地方欢迎讨论和指正。
如果能给观看的你带来收获,那就是最好不过了。

人生得意须尽欢, 桃花坞里桃花庵
点个关注呗,对,不信你点试试?
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,230评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,261评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,089评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,542评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,542评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,544评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,922评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,578评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,816评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,576评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,658评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,359评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,920评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,859评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,381评论 2 342

推荐阅读更多精彩内容