你还在为列表[单选]、[多选]写重复的逻辑吗

栏目: IOS · Android · 发布时间: 5年前

内容简介:项目中经常性会碰到列表的单选、多选,实现起来好像也不难,但是最近项目有好多个需要单选/多选的页面,看到设计稿的一瞬间,脑子灵光一闪,为啥不把这些简单而又繁琐的逻辑给封装起来呢(懒癌发作)?于是就有了下面的小东西(开源库)...废话少说,先上图:

项目中经常性会碰到列表的单选、多选,实现起来好像也不难,但是最近项目有好多个需要单选/多选的页面,看到设计稿的一瞬间,脑子灵光一闪,为啥不把这些简单而又繁琐的逻辑给封装起来呢(懒癌发作)?

于是就有了下面的小东西(开源库)...

二 功能

1.列表单选

  • 普通单选
  • 预选中
  • 不能取消
  • 多类型
  • 多列表

2.列表多选

  • 普通多选
  • 预选中
  • 全选/取消全选
  • 多类型
  • 多列表

3.优点

Adapter.notifyItemChange

三 效果

废话少说,先上图:

1.单选

你还在为列表[单选]、[多选]写重复的逻辑吗

2.多选

你还在为列表[单选]、[多选]写重复的逻辑吗

四 使用

1.配置

首先在你的工程根目录的 gradle 文件下添加以下配置:

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}
复制代码

接着就可以在你的moudle,一般是 app 的 gradle 文件下添加依赖:

implementation 'com.github.gminibird:CheckHelper:1.0'
复制代码

最后那个1.0是版本号,可以上 GitHub 上看最新的,然后就可以愉快的玩耍啦。

2.使用

  • 创建CheckHelper实例
    SingleCheckHelper mCheckHelper = new SingleCheckHelper();
    //or
    MultiCheckHelper mCheckHelper = new MultiCheckHelper();
    复制代码
  • 注册选择器
    mCheckHelper.register(String.class, new CheckHelper.Checker<String, LwViewHolder>() 
    @Override
    public void check(String s, LwViewHolder holder) {
        //选中状态
        holder.itemView.setBackgroundColor(0xFF73E0E4); //蓝色
        holder.setChecked(R.id.checkbox, true);
    }
    @Override
    public void unCheck(String s, LwViewHolder holder) {
        //非选中状态
        holder.itemView.setBackgroundColor(0xFFFFFFFF);  //白色
        holder.setChecked(R.id.checkbox, false);
    }
    });
    复制代码
  • 绑定到Adapter中
    @Override
    protected void onBind(@NonNull LwViewHolder holder, @NonNull String item) {
        //这里用了自己封装的Adapter,相当于onBindViewHolder方法
        mCheckHelper.bind(item, holder, holder.itemView);
    }
    复制代码

然后,然后就完成了。。。运行就可以看到想要的效果,选中的数据可以调用相应 CheckHelper 实例的 getXXX() 获取。

五 实现原理

总的原理其实很简单,就是对应的 CheckHelper 实现类内部维护一些选中的数据。下面细说下具体实现:

1. 模板类 CheckHelper

CheckHelper 是目前两个实现类的基类,提供了一些基础的公共功能,比如设置监听器,注册选择器等,其实就是一个模板模式,把公共部分以及执行顺序都定了,然后交由子类完成具体的数据增改。

里面有两个重要的方法,一个是 bind() ,另一个是 select() ,分别对应了 onBindViewHolder 以及 onClick (点击)方法:

public final void bind(final Object d, final RecyclerView.ViewHolder v, View clickedView) {
    if (clickedView == null) {
        throw new NullPointerException("ClickedView can not be null!");
    }
    bind(d, v, isChecked(d, v)); //注释1
    clickedView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            select(d, v);  //注释2
        }
    });
}
复制代码

我们在 onBindViewHolder() 方法中绑定的 bind() 方法最终会调用这个方法,先看 注释1注释1 里的bind方法里面做了一系列的监听器的回调:

public void bind(Object d, RecyclerView.ViewHolder v, boolean toCheck) {
    Checker checker = mCheckerMap.get(d.getClass());
    if (checker != null) {
        if (toCheck) {
            checker.check(d, v);
        } else {
            checker.unCheck(d, v);
        }
    }
    OnCheckListener checkListener = mCheckListenerMap.get(d.getClass());
    if (checkListener != null) {
        checkListener.onCheck(d, v, toCheck);
    }
    onBindListener bindListener = mOnBindListenerMap.get(d.getClass());
    if (bindListener != null) {
        bindListener.onBind(d, v, toCheck);
    }
}
复制代码

其中包括 Checker ,也就是我们注册为非选中和选中状态设置的选择器会被调用,然后就是 OnCheckListener 以及 onBindListener ,这两个我们都可以add 进去。

再返回看最上面的bind() 方法里面的 注释2 ,调用了一系列回调后,然后便为 item 的某个 view 设置一个监听,点击后就会执行 select 方法, select 方法里面也是做了一系列回调,基本和上面的方法一致。所以子类只要重写这两个方法,并实现相应的数据操作即可。

2. SingleCheckHelper 单选

单选其实不难,但有一点比较难搞:

选中后怎么把上一次选中给取消?

如果按照平时的写法,我们在Bean里面增加一个 isChecked 字段,然后选择这个时将当前选中置为 true ,接着将上一个选择的置为 false 最后调用 adapter 刷新一下就可以了。

但是这里没有依赖具体的Bean,也没有新增字段,那怎么弄呢,后来想到了一个小技巧,我没有依赖Bean,但是可以在 ViewHolder 里面存储信息,所以就有下面的代码:

@Override
public void select(Object d, RecyclerView.ViewHolder v, boolean toCheck) {
    if (toCheck) {
        unCheckPre(d);  //注释1
        setTag(v);    //注释2
        this.v = v;
        this.d = d;
    } else {
        if (!canCancel){
            return;
        }
        clearTag(v);  //注释3
        this.d = null;
        this.v = null;
    }
    super.select(d, v, toCheck);
}
复制代码

逻辑也很简单,如果是选中状态,而且存有tag,那么说明是之前已经有选中的,就将之前选中的tag清除,然后再把当前的选中设置一个tag,如果是取消选中,那么就将tag给清除掉:

private void unCheckPre(Object d) {
    if (this.d == null || this.d.equals(d)) {
        return;
    }
    if (this.d != null && this.v != null && this.v.itemView.getTag(TAG) != null) {
        //当上一个选中存在并且可见时置为非选
        bind(d, v, false);
    }
}

private void setTag(RecyclerView.ViewHolder v) {
    if (v != null) {
        v.itemView.setTag(TAG, TAG_VALUE);
    }
}
复制代码

接着就回调父类的一系列回调接口了。

3.MultiCheckHelper 多选

多选类主要是靠一个 Map 来维护选中的数据,每个数据类型对应一个 Set ,选中和非选中就调用相应的方法更新数据,没有很大难点。

protected HashMap<Class, Set<?>> mMap;

@SuppressWarnings("unchecked")
public void add(Object d) {
    Set<Object> set = (Set<Object>) mMap.get(d.getClass());
    if (set == null) {
        set = new HashSet<>();
        mMap.put(d.getClass(), set);
    }
    set.add(d);
}
public void remove(Object d) {
    Set set = mMap.get(d.getClass());
    if (set != null) {
        set.remove(d);
        if (set.size() == 0) {
            mMap.remove(d.getClass());
        }
    }
}
复制代码

由于作者水平有限,如果有更好的方法欢迎探讨。

written by gminibird

源码戳上面 ^^^


以上所述就是小编给大家介绍的《你还在为列表[单选]、[多选]写重复的逻辑吗》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

MySQL入门很简单

MySQL入门很简单

黄缙华 / 清华大学出版社 / 2011-1 / 59.50元

《MySQL入门很简单》从初学者的角度出发,由浅入深,循序渐进地介绍了mysql数据库应用与开发的相关知识。书中提供了大量操作mysql数据库的示例,还提供了大量实例和上机实践内容,供读者演练。《MySQL入门很简单》附带1张dvd光盘,内容为与《MySQL入门很简单》内容完全配套的多媒体教学视频和《MySQL入门很简单》涉及的源代码。 《MySQL入门很简单》共分5篇。第1篇介绍数据库的基......一起来看看 《MySQL入门很简单》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具