Android 万能适配器BRVAH

概述

在Android开发过程中,我们经常会用到adapter。因为adapter在基本使用的过程中,代码比较繁琐,于是进行一个简单封装,使调用起来更加简单便捷。这节就来讲讲这个适配器的封装吧。

前言

在Android开发过程中,我们经常会用到adapter。因为adapter在基本使用的过程中,代码比较繁琐,于是进行一个简单封装,使调用起来更加简单便捷。这节就来讲讲这个适配器的封装吧。

今天涉及的内容:

  1. adapter库依赖
  2. 封装类ComAdapter和GroupAdapter概述
  3. 通用适配器ComAdapter的使用
  4. 分组适配器GroupAdapter的使用
  5. MainActivity中调用示例
  6. 效果图和项目结构图

先来波adapter使用的效果图吧


image

一. adapter库依赖

Github地址
本adapter的封装是建立在一个第三方库的基础之上的。在使用之前,你需要添加该库的依赖:
将JitPack存储库添加到您的构建文件中(项目根目录下build.gradle文件):

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}

添加依赖项以最新版本为准:

dependencies {
    implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.34'
}

二.封装类ComAdapter和GroupAdapter概述

适配器库BaseRecyclerViewAdapterHelper是一个专注adapter的库,里面有一个适配器基类:BaseQuickAdapter,为了方便日常调度使用,我在BaseQuickAdapter基础上再度扩展,分别整合了两个adapter基类:ComAdapter和GroupAdapter。
ComAdapter:基于一般的列表或九宫格布局的使用
GroupAdapter:基于简单的分组列表展示使用。

三.通用适配器ComAdapter的使用

ComAdapter是一个通用适配器基类,里面集成了adapter创建需要的一些基本方法,包括控件初始化,获取布局对象,加载动画,列表数据加载,控件点击事件监听等方法。 当你要实现一个线性列表,需要创建adapter的时候,继承ComAdapter可以帮你快速实现自己的adapter。

3.1 继承ComAdapter,写自己的Adapter

当RecyclerView加载列表的时候,需要一个适配器(NameAdapter),你可以像这样快速来创建它:

public class NameAdapter<T>extends ComAdapter {
    private TextView mTvName;
    public NameAdapter(List<T> data, Context context) {
        //加载布局和数据
        super(R.layout.item_layout, data, context);
    }
    @Override
    public <T>void initView(BaseViewHolder viewHolder, T obj) {
        //控件初始化
        mTvName=viewHolder.getView(R.id.tv);
    }
    @Override
    public <T>void initData(BaseViewHolder viewHolder, T obj) {
        String name=obj.toString();
        mTvName.setText(name);
    }
    @Override
    public <T>void setListener(BaseViewHolder viewHolder, T obj) {
        //添加控件监听
        addOnClickListener(mTvName,viewHolder,obj);
    }
}
3.2 线性布局调用
mNames=new ArrayList<>();
//for (int i = 0; i < 10; i++) {
//    mNames.add("小黄"+i);
//}
mNameAdapter=new NameAdapter<>(mNames,MainActivity.this);
mNameAdapter.setRecyclerLinearManager(mRecyclerView);
3.3 九宫格布局调用
mNames=new ArrayList<>();
//for (int i = 0; i < 10; i++) {
//    mNames.add("小黄"+i);
//}
mNameAdapter=new NameAdapter<>(mNames,MainActivity.this);
mNameAdapter.setRecyclerGridManager(mRecyclerView,4);
3.4 设置分割线,返回RecyclerView.ItemDecoration对象

//设置线性布局分割线
LinearDividerItemDecoration linearDivider=mNameAdapter.setLinearLayoutItemSpace(mRecyclerView,5,R.color.colorAccent);
//设置九宫格局分割线
GridDividerItemDecoration gridDivider=mNameAdapter.setGridLayoutItemSpace(mRecyclerView,5,R.color.colorAccent);

3.5 移除分割线
/**移除RecycleView间距**/
removeItemSpace(RecyclerView recyclerView,  RecyclerView.ItemDecoration divider)
3.6 点击事件
       //点击事件
       mNameAdapter.setOnItemClickListener(new AdapterHelper.OnItemClickListener() {
            @Override
            public void itemClickListener(View view, BaseViewHolder viewHolder, Object obj) {
                switch (view.getId()) {
                    case R.id.tv:
                        ToastUtil.shortShow("====1====="+obj.toString());
                        break;
                    default:
                        break;
                }
            }
        });

四. 分组适配器GroupAdapter的使用

GroupAdapter是一个列表分组显示的适配器基类,里面集成了adapter创建需要的一些基本方法,包括控件初始化,获取布局对象,加载动画,列表数据加载,控件点击事件监听等方法。 当你要船创建一个分组显示功能的adapter,继承GroupAdapter可方便快捷实现

4.1 javaBean继承SectionEntity类

GroupAdapter显示的数据,都需要用javaBean进行封装。并且JavaBean需要继承SectionEntity类,然后重写含(boolean isHeader, String header)参数的构造方法。 以Person对象为例,你需要这样处理:

public class Person extends SectionEntity {
    private String name;
    private int age;
    public Person(boolean isHeader, String header) {
        super(isHeader,header);
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
4.2 继承GroupAdapter,写自己的adapter

然后写一个自己的adapter,继承自GroupAdapter,以PersonAdapter为例:

public class PersonAdapter<T> extends GroupAdapter {
    //header
    private TextView mTvHeader;
    //item
    private TextView mTvItem;
    public PersonAdapter(List<T> data, Context context) {
        super(R.layout.item_layout, R.layout.header_layout, data,context);
    }
    @Override
    protected void convertHead(BaseViewHolder viewHolder, SectionEntity item) {
        //标题相关所有都在此处理
        //标题初始化
        mTvHeader=viewHolder.getView(R.id.tv_title);
        //标题数据处理
        mTvHeader.setText(item.header);
        //标题点击事件
        addOnClickListener(mTvHeader,viewHolder,item);
    }
    @Override
    public <T>void initView(BaseViewHolder viewHolder, T obj) {
        //item初始化
        mTvItem=viewHolder.getView(R.id.tv);
    }
    @Override
    public <T>void initData(BaseViewHolder viewHolder, T obj) {
        //item数据处理
        Person person= (Person) obj;
        mTvItem.setText("姓名:"+person.getName()+"     年龄:"+person.getAge());
    }
    @Override
    public <T>void setListener(BaseViewHolder viewHolder, T obj) {
        //item中控件监听
        addOnClickListener(mTvItem,viewHolder,obj);
    }
}

其中PersonAdapter(List data, Context context)构造方法的super方法中,要引入两个布局id,一个是item的一个是header的。 Header相关方法都在convertHead中处理。item的相关处理在initView,initData和setListener方法中进行。

4.3 线性布局使用
       mPersonList=new ArrayList<>();
       //for (int i = 0; i < 10; i++) {
       //Person person;
       //if(i%7==0){//header
       //   person=new Person(true,"标题"+i);
       //}else{//item
       //   person=new Person(false,null);
       //   person.setName("小黑"+i);
       //   person.setAge(25+i);
       // }
       //   mPersonList.add(person);
       //}
       mPersonAdapter=new PersonAdapter<>(mPersonList,MainActivity.this);
       mPersonAdapter.setRecyclerLinearManager(mRecyclerView);
4.4 九宫格布局使用
        mPersonList=new ArrayList<>();
        //for (int i = 0; i < 10; i++) {
        //Person person;
        //if(i%7==0){//header
        //   person=new Person(true,"标题"+i);
        //}else{//item
        //   person=new Person(false,null);
        //   person.setName("小黑"+i);
        //   person.setAge(25+i);
        // }
        //   mPersonList.add(person);
        //}
        mPersonAdapter=new PersonAdapter<>(mPersonList,MainActivity.this);
        mPersonAdapter.setRecyclerGridManager(mRecyclerView,3);
4.5 设置分割线,返回RecyclerView.ItemDecoration对象

线性布局的时候,可以像下面这样设置分割线:

//线性布局分割线
LinearDividerItemDecoration linearDivider=mPersonAdapter.setLinearLayoutItemSpace(mRecyclerView, 5, R.color.colorAccent);

注意: 在实现分组适配器<即继承GroupAdapter的adapter>不能使用setGridLayoutItemSpace给列表设置分割线,会出现ui上显示的bug,为了避免 用户使用不当,我已经将GroupAdapter类中的setGridLayoutItemSpace抛出异常并做以错误提示。大家若还是需要在分组九宫格布局中做分割线的话, 需要自己在布局中,或者在adapter中处理数据的时候,用代码来实现分割线效果。

4.6 移除分割线
/**移除RecycleView间距**/
removeItemSpace(RecyclerView recyclerView, RecyclerView.ItemDecoration divider)
4.7 点击事件

若要设置adapter的点击事件,你可以像下面这样写:

        //点击事件
        mPersonAdapter.setOnItemClickListener(new AdapterHelper.OnItemClickListener() {
            @Override
            public void itemClickListener(View view, BaseViewHolder viewHolder, Object obj) {
                Person person= (Person) obj;
                switch (view.getId()) {
                    case R.id.tv_title://header
                        ToastUtil.shortShow("===="+person.header+"===");
                        break;
                    case R.id.tv://item
                        ToastUtil.shortShow("===="+person.getName()+"===");
                        break;
                    default:
                        break;
                }
            }
        });

五.MainActivity中调用示例

下面贴出adapter在MainActivity中使用的代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button mBtn1;
    private Button mBtn2;
    private Button mBtn3;
    private Button mBtn4;
    private RecyclerView mRecyclerView;
    private List<String>mNames;
    private NameAdapter<String>mNameAdapter;
    private List<Person>mPersonList;
    private PersonAdapter<Person>mPersonAdapter;
    private LinearDividerItemDecoration mLinearDivider;
    private GridDividerItemDecoration mGridDivider;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        setListener();
    }
    private void initData() {
        mBtn1 = findViewById(R.id.btn1);
        mBtn2 = findViewById(R.id.btn2);
        mBtn3 = findViewById(R.id.btn3);
        mBtn4 = findViewById(R.id.btn4);
        mRecyclerView = findViewById(R.id.rv);
        mBtn1.setText("通用线性");
        mBtn2.setText("通用九宫");
        mBtn3.setText("分组线性");
        mBtn4.setText("分组九宫");
    }
    private void setListener() {
        mBtn1.setOnClickListener(this);
        mBtn2.setOnClickListener(this);
        mBtn3.setOnClickListener(this);
        mBtn4.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn1://通用布局线性测试
                commonLinearLayout();
                break;
            case R.id.btn2://通用布局九宫格测试
                commonGridLayout();
                break;
            case R.id.btn3://分组布局线性测试
                diffGropLinearLayout();
                break;
            case R.id.btn4://分组布局九宫格测试
                diffGropGridLayout();
                break;
            default:
                break;
        }
        //点击事件
        commonDiffClick();
    }
    private void initCommonData(){
        //通用布局
        if(mNames==null) {
            mNames = new ArrayList<>();
        }
        mNames.clear();
        for (int i = 0; i < 10; i++) {
            mNames.add("小黄" + i);
        }
    }
    private void initdiffGropData(){
        //分组布局
        if(mPersonList==null) {
            mPersonList = new ArrayList<>();
        }
        mPersonList.clear();
        for (int i = 0; i < 10; i++) {
            Person person;
            if(i%7==0){//header
                person=new Person(true,"标题"+i);
            }else{//item
                person=new Person(false,null);
                person.setName("小黑"+i);
                person.setAge(25+i);
            }
            mPersonList.add(person);
        }
    }
    /**
     * 通用布局线性测试
     **/
    private void commonLinearLayout() {
        initCommonData();
        mNameAdapter = new NameAdapter<>(mNames, MainActivity.this);
        mNameAdapter.setRecyclerLinearManager(mRecyclerView);
        //清除旧的分割线
        mNameAdapter.removeItemSpace(mRecyclerView,mLinearDivider);
        mNameAdapter.removeItemSpace(mRecyclerView,mGridDivider);
        //设置分割线
        mLinearDivider=mNameAdapter.setLinearLayoutItemSpace(mRecyclerView, 5, R.color.colorAccent);
    }
    /**
     * 通用布局九宫格测试
     **/
    private void commonGridLayout() {
        initCommonData();
        mNameAdapter = new NameAdapter<>(mNames, MainActivity.this);
        mNameAdapter.setRecyclerGridManager(mRecyclerView, 3);
        //清除旧的分割线
        mNameAdapter.removeItemSpace(mRecyclerView,mLinearDivider);
        mNameAdapter.removeItemSpace(mRecyclerView,mGridDivider);
        //设置分割线
        mGridDivider=mNameAdapter.setGridLayoutItemSpace(mRecyclerView, 5, R.color.colorAccent);
    }
    /**
     * 分组布局线性测试
     **/
    private void diffGropLinearLayout() {
        initdiffGropData();
        mPersonAdapter=new PersonAdapter<>(mPersonList,MainActivity.this);
        mPersonAdapter.setRecyclerLinearManager(mRecyclerView);
        //清除旧的分割线
        mNameAdapter.removeItemSpace(mRecyclerView,mLinearDivider);
        mNameAdapter.removeItemSpace(mRecyclerView,mGridDivider);
        //设置分割线
        mLinearDivider=mPersonAdapter.setLinearLayoutItemSpace(mRecyclerView, 5, R.color.colorAccent);
    }
    /**
     * 分组布局九宫格测试
     **/
    private void diffGropGridLayout() {
        initdiffGropData();
        mPersonAdapter=new PersonAdapter<>(mPersonList,MainActivity.this);
        mPersonAdapter.setRecyclerGridManager(mRecyclerView,3);
        //清除旧的分割线
        mNameAdapter.removeItemSpace(mRecyclerView,mLinearDivider);
        mNameAdapter.removeItemSpace(mRecyclerView,mGridDivider);
    }
    /**点击事件**/
    private void commonDiffClick(){
        //通用布局点击事件
        if(mNameAdapter!=null) {
            mNameAdapter.setOnItemClickListener(new AdapterHelper.OnItemClickListener() {
                @Override
                public void itemClickListener(View view, BaseViewHolder viewHolder, Object obj) {
                    switch (view.getId()) {
                        case R.id.tv:
                            ToastUtil.shortShow("====1=====" + obj.toString());
                            break;
                        default:
                            break;
                    }
                }
            });
        }
        //分组布局点击事件
        if(mPersonAdapter!=null) {
            mPersonAdapter.setOnItemClickListener(new AdapterHelper.OnItemClickListener() {
                @Override
                public void itemClickListener(View view, BaseViewHolder viewHolder, Object obj) {
                    Person person = (Person) obj;
                    switch (view.getId()) {
                        case R.id.tv_title://header
                            ToastUtil.shortShow("====" + person.header + "===");
                            break;
                        case R.id.tv://item
                            ToastUtil.shortShow("====" + person.getName() + "===");
                            break;
                        default:
                            break;
                    }
                }
            });
        }
    }
}

六. 效果图和项目结构图

效果图


image

项目结构图


image

最后

虽然万能适配器方便好用,但是我还是推荐使用原生写法,因为原生写法更灵活,不会出现莫名的问题。万能适配器的动画目前可能有点毛病,谨慎使用列表动画!

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

推荐阅读更多精彩内容