美文网首页java收集Andorid的好东西ITBOX
【干货】Android真正的“万能”Adapter

【干货】Android真正的“万能”Adapter

作者: FullStack | 来源:发表于2016-04-13 21:49 被阅读13550次

最近看到不少封装Adapter的库,但是都感觉不够方便。今天给大家介绍一个真正的“万能”Adapter(源码地址),精髓就在于一个Adapter同时适用于RecyclerView、ListView、GridView、Spinner等。

源码结构图.png

主要特性

  • 减少大量代码!减少大量代码!减少大量代码!(重说三)
  • 支持header和footer。
  • 支持RecyclerView的item点击事件。
  • 隐藏ViewHolder相关的所有代码。
  • 一个SuperAdapter同时支持BaseAdapterRecyclerView.Adapter
  • 封装Adapter数据源变动操作。
  • item加载动画。

如何使用

如果是个简单布局的Adapter,可以简写为如下示例代码:

public class SingleAdapter extends SuperAdapter<MockModel> {
    public SingleAdapter(Context context, List<MockModel> list, int layoutResId) {
        super(context, list, layoutResId);
    }

    @Override
    public void onBind(SuperViewHolder holder, int viewType, int position, MockModel item) {
        holder.setText(R.id.tv_name, item);
    }
}

可以看出除了构造方法,只需要重写一个onBind()方法就够了。
然后在Activity(or Fragment)中调用:

mSingleAdapter = new RecyclerSingleAdapter(context, list, R.layout.your_item);  
recyclerView.setAdapter(mSingleAdapter);

其中SuperViewHolder为通用的holder封装类,提供了一系列的便捷方法(ChainSetter),而且可以链式调用,如:

ChainSetter部分方法.png
还可以使用getView(int viewId)来确定一个item的view:
@Override
public void onBind(SuperViewHolder holder, int viewType, int position, String item) {
    holder.setText(R.id.tv_name, item);
    ImageView img = holder.getView(R.id.iv_portrait);
    img.setImageResource(resId);
}

当然也支持多item布局,需要提供一个IMulItemViewType<T>接口:

public class MultipleAdapter extends SuperAdapter<MockModel> {
    public MultipleAdapter(Context context, List<MockModel> list, IMulItemViewType<MockModel> multiItemViewType) {
        super(context, list, multiItemViewType);
    }

    @Override
    public void onBind(SuperViewHolder holder, int viewType, int position, MockModel item) {
        switch (viewType) {
            case 0:
                holder.setText(R.id.tv_name, item.getName());
                break;
            case 1:
                holder.setText(R.id.tv_name, item.getName());
                holder.setImageResource(R.id.iv_portrait, R.mipmap.ic_launcher);
                holder.setText(R.id.tv_age, String.valueOf(item.getAge()));
                break;
        }
    }
}

然后调用(注意构造方法的参数与单布局的区别):

multiAdapter = new MultipleAdapter(getContext(), list, new IMulItemViewType<MockModel>() {
                @Override
                public int getItemViewType(int position, MockModel mockModel) {
                    if (position % 2 == 0) {
                        return 0;
                    }
                    return 1;
                }

                @Override
                public int getLayoutId(int viewType) {
                    if (viewType == 0) {
                        return R.layout.item_type1;
                    }
                    return R.layout.item_type2;
                }

                @Override
                public int getViewTypeCount() {
                    return 2;
                }
            });
recyclerView.setAdapter(mMultiAdapter);

如果使用的是RecyclerView,在使用多布局时,还可以使用SimpleMulItemViewType类(继承自IMulItemViewType),因为getViewTypeCount()方法仅在使用ListView、GridView等控件时是必须提供的:

mAdapter = new MultipleAdapter(getContext(), models, new SimpleMulItemViewType<MockModel>() {
    @Override
    public int getItemViewType(int position, MockModel mockModel) {
        if (position % 2 == 0) {
            return 0;
        }
        return 1;
    }

    @Override
    public int getLayoutId(int viewType) {
        if (viewType == 0) {
            return R.layout.item_type1;
        }
        return R.layout.item_type2;
    }
});
recyclerView.setAdapter(mAdapter);

如果不想在创建Adapter时提供IMulItemViewType接口,也可以在Adapter中重写offerMultiItemViewType()方法:

@Override
protected IMulItemViewType<MockModel> offerMultiItemViewType() {
    return new IMulItemViewType<MockModel>() {
        @Override
        public int getViewTypeCount() {
                return 2;
        }

        @Override
        public int getItemViewType(int position, MockModel mockModel) {
            if (position % 2 == 0) {
                return 0;
            }
            return 1;
        }

        @Override
        public int getLayoutId(int viewType) {
            if (viewType == 0) {
                return R.layout.item_type1;
            }
            return R.layout.item_type2;
        }
    };
}

然后在创建Adapter时提供null
multiAdapter = new MultipleAdapter(context, list, null);


开启加载动画:
adapter.openLoadAnimation();
你也可以指定动画时常和类型:
adapter.openLoadAnimation(long duration, new SlideInBottomAnimation());
默认的加载动画只执行一次,如果你想每次显示item的时候都执行,可以设置
adapter.setOnlyOnce(false);
当然实现自定义的动画也很简单,可以通过实现BaseAnimation接口来创建你心仪的动画。


至于header和footer的使用,就更简单啦!adapter.addHederView(view)就可以添加一个Header了,你可以使用的全部api如下:

Header和Footer相关的api.png

最后再贴一遍源码地址,欢迎提交代码、bug以及讨论 :) 能分享到自己的朋友圈就更好啦 _ ……

QQ群:271849001(新)

qq交流群.png
感谢base-adapter-helper项目提供的灵感。

转载请联系作者

相关文章

网友评论

  • 83f379da4db4:请问一下只有2条数据但是onBand 刷新了6次是什么原因啊?导致里面的图片显示重复。
  • 远方的鸢:感谢作者
  • f6a4eb3ab3e6:学习一下源码。谢谢了
  • 苏易川:大赞👍👍👍👍👍
  • Aiden_9:非常实用,开眼界,大神
    FullStack:@Tmgg19 可以在github上给个star哦
  • cf908b4323ca:很好用,问下这个用加混淆规则吧。
    FullStack:@J2A 不客气,可以看一下github上的demo,用法都在里面
    cf908b4323ca:@FullStack 好的。Thanks。
    FullStack:@J2A 不用的
  • 0c87575a416f:为啥我涮新适配器的时候没啥反应呢,item没变啊
  • Richair_Ann:楼主 ,请教一个问题,我的item中同时有文字跟网络图片,现在使用holder,getView(id)方法 发现过时,想请教 这个方法还可不可以使用,新的方法是什么?我使用的Glide 加载网络图片
    FullStack:@Richair_Ann 不客气,有问题可以使用github上的issue,更方便。
    Richair_Ann:@FullStack 谢谢大神的贡献
    FullStack:@Richair_Ann 还可以用,替代方法是holder.findviewbyid
  • 70701e285746:有两个问题请教一下:1:compile 'com.android.support:recyclerview-v7:25.1.0' 这个也需要导入吗?2:holder.getView(R.id.xx) 这个方法过期了,有什么新的方法代替?谢谢
    70701e285746:和PullToRefresh配合时调用adapter.notifyDataSetChanged() 界面会翻一页,和原生的adapter的效果不一样
    FullStack:需要导入, findViewById
  • riceeeeeeee:非常方便,已经用在项目中了,唯一觉得别扭的地方就是notifyDataSetChanged()没效果。
    riceeeeeeee:@FullStack 嗯,一直获取最新的版本3.+
    FullStack:@HxH_RORO 用的是最新的版本吗?
  • MrTrying:在么?github上有个问题,我添加这一句的时候是build不出来的
    compile 'org.byteam.superadapter:superadapter:latestVersion'
    我改成了下面这句就build成功了,楼主是不是看看这个地方
    compile 'org.byteam.superadapter:superadapter:latest.release'
    吕中宜:@MrTrying 如果想一直用最新的,你就这么写
    compile 'org.byteam.superadapter:superadapter:3.+'
    MrTrying: @FullStack 我知道那样可以,就是想问问github上是不是有问题,有问题就改改不然直接copy就不对
    FullStack:@MrTrying 版本号改成3.6.2
  • 吕中宜:首先感谢作者,我之前一直使用你这个库,确实给我带来了不少方便,不过我当前使用的这个版本有个bug,发生bug的版本是3.6.1,我不知道其他版本有没有这个问题,就是adapter.notifyDataSetChanged();的时候不刷新数据,我之前也一直检查是否是我数据源对象的变动导致的,我测试了一天,最后换了一下张鸿洋的那个库,发现就可以更新了,不过他那个的listview和recyclerview的adapter是分开的两个库,这里提一下bug,我就不去github提了
    吕中宜:@FullStack 我没有使用adapter中的增删改,我是直接对数据源的操作,mvp模式,p中对list操作,调用v中的刷新
    ```
    public void addDevice(DeviceInfo deviceInfo) {
    if (!isContains(deviceInfo.getAddress())) {
    devices.add(deviceInfo);
    JLog.v(deviceInfo.getAddress());
    v.updateListView(devices);
    }
    }
    ```
    ```
    @Override
    public synchronized void updateListView(List<DeviceInfo> devices) {
    if (deviceInfoAdapter == null) {
    deviceInfoAdapter = new DeviceInfoAdapter(this, R.layout.item_device, devices,
    deviceInfo -> {
    shortToast(deviceInfo.toString());
    });
    rvDevices.setAdapter(deviceInfoAdapter);
    } else {
    deviceInfoAdapter.notifyDataSetChanged();
    }
    }
    ```
    p中的这个数据源只在static中new了一下,其余时候清空操作都是.clear的,没有new过数据源,顺便提一下,我使用的RecyclerView版本是24.1.1
    FullStack:@吕中宜 如果你是使用adapter中的增删改方法,就不需要自己调用notify了,可以加群271849001 交流~
    FullStack:@吕中宜 可以把关键代码贴到issue里,这样方便我找问题哦~
  • 6e40af8b4506:怎样加载网络图片啊,没看到方法
  • 豆奶不好喝:楼主,用的时候 发现 嵌套型的 就没法使用欸 比如listview 嵌套一个gridview 在里面没发写gridview的东西 是吗?
    FullStack:@豆奶不好喝 这个库对使用场景没有影响的,如果原生方式支持,这个库就支持。 :flushed: 请问你是怎么用的,可以在github上提issue~
  • 鸡蛋掉了:还不错,但是没有封装是否滚动的方法,加载图片滚动时应该不加载的。还有设置值时内部应该做空值的判断等等要加的东西也不少。
    FullStack:@鸡蛋掉了 感谢反馈,后期会加上的。 :blush:
  • Wing_Li:非常棒,非常棒,非常棒!
    FullStack:@Wing_Li 谢谢支持:blush:
  • 心里有颗小星星:Get, 写的真不错~~~
    心里有颗小星星:@vcs 已star~
    FullStack:@Cherno 欢迎star一下源码:smile:
  • 知县有点小心事儿:想问下代码框怎么打出来的
    知县有点小心事儿:@vcs 嗯 谢了
    FullStack:@知县有点小心事儿 markdown语法,很简单的。
  • binwin20:发现bug:`mAdapter.addAll(2, list);` mAdapter 从 SuperAdapter 继承的.
    FullStack:@binwin20 谢谢反馈,可以提issue哦。 :relaxed:
  • yulongsun:如果item要加载网络大图呢?
    FullStack:@yulongsun ImageView img = getView(id); 然后你可以使用任何主流框架加载图片给这个img
  • fb879d10f593:放入空数据,然后刷新数据好像不行
    FullStack:@Kuan 这样操作是没问题的
    fb879d10f593:@vcs 比如ArrayList<Model> aLLModels= new ArrayList<>();
    SimpleAdapter adapter= new SimpleAdapter(SActivity.this, aLLModels);
    这样先放list进去先生成adapter,给其他地方用,然后网络获取数据后填充aLLModels,之后在刷新界面。
    FullStack:@Kuan 空数据默认不执行操作,你想要什么效果呢
  • 74f2385a62c0:收藏研究下
  • 豆奶不好喝:我看了下源码了,但是我在as里面想使用,compile 'org.byteam.superadapter:superadapter:latestVersion@aar' 加进来的时候 这个latestVersion 是多少呢?
    FullStack:@豆奶不好喝 3.0
  • 0accf1d234ee:受益匪浅
    FullStack:@红狮传说 我感到很荣幸:grin:
  • jiekekeji:我试了一下 使用notifyDataSetChanged怎么刷新不了呢?? :smile:
    FullStack:@jiekekeji 可以提issue哦,或者看看demo:grin:
  • 97d281b24b28:学习中,刚开始接触adapter,觉得好难懂里面的机制
    FullStack:@小点点儿 先学会用 等用的熟练了 再看实现机制。
  • 0b8aaf76d30b:干货,学习下
  • 小呀么小黄鸡:我也是对比了很多github上的adapter——stupidAdapter、commonAdapter、以及这里提到的superAdapter,最后选择了这种 很巧 在简书首页看到这篇文章 没想到真是介绍superAdapter的 只能说好东西总会被发现的
    FullStack:@小呀么小黄鸡 谢谢您的支持,如果发现bug或者有其他疑问,可以随时联系我。
    小呀么小黄鸡:@vcs 对比了下头像才发现是作者!其实还有个原因在于commit的次数 :smile: 真是勤奋的作者!
    FullStack:你雪亮的眼光:smile:
  • f590affc50d2: 厉害啊 收藏咯
  • RoadToGeek:干货,学习学习
  • 5bde03e172cf:我还是一个初学者,虽然看的不是很懂,但是我觉得写的不错,慢慢琢磨!
    FullStack:@心如止水11 可以下载源码看看,很简单的:blush:
  • MrTrying:很厉害啊!继承Recyclereview.Adapter同时实现ListAdapter等interface,统一了使用方式
    FullStack:@MrTrying :grin:是哦
  • Jenchar:可以学习,这段时间老是写adapter,好肥费时间
    FullStack:@Jenchar :grin:减少无聊的重复代码
  • 03066c741ad7:大写的牛逼
  • 新精英俱乐部:真是活久见呀
    新精英俱乐部:@vcs 搞了这么长时间Android开发了,才知道有这么个强大的adapter,真是get√了,谢作者分享。
    FullStack:@行知E人 咋了:flushed:
  • da7091fa95b5:感觉用id找view很麻烦啊.....
    Aiden_9:你想使用butterknife吗
    da7091fa95b5:@vcs 我的意思是每次用的时候都要用他的ID去找....很麻烦
    FullStack:@da7091fa95b5 其实就是findViewById的封装 :grin:
  • 谭冉冉:非常好.目前见过的最好的
    谭冉冉:@vcs 新提交了一个issues .
    FullStack:@谭冉冉 谢谢,欢迎提交新想法 :grin:
  • 路痴欧巴:先mark
    FullStack:@路痴欧巴 谢谢,欢迎star:grin:
  • 9c6f020c1e95:收藏!
  • FullStack: :grin:
    但悟我心:@vcs 恩,看看源码写的不错哦,一起交流一下吧 :grin:
    FullStack:@但悟我心 十分感谢您的认可 :smile:
    但悟我心:@vcs 已打赏

本文标题:【干货】Android真正的“万能”Adapter

本文链接:https://www.haomeiwen.com/subject/olcglttx.html