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

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

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

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

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

二 功能

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

源码戳上面 ^^^


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

查看所有标签

猜你喜欢:

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

Automate This

Automate This

Christopher Steiner / Portfolio / 2013-8-9 / USD 25.95

"The rousing story of the last gasp of human agency and how today's best and brightest minds are endeavoring to put an end to it." It used to be that to diagnose an illness, interpret legal docume......一起来看看 《Automate This》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具