A bullshit

In the project, we often encounter the list of single and multi-selection, which seems to be easy to implement, but recently there are a lot of single/multi-selection pages in the project, the moment I see the design draft, my mind flashes, why not encapsulate these simple and tedious logic (lazy cancer attack)?

Hence the following little thing (open source library)…

The second function

1. List option

  • Ordinary radio
  • primary
  • Cannot cancel
  • g
  • More than a list of

2. Select multiple lists

  • Ordinary multi-select
  • primary
  • Select all/deselect all
  • g
  • More than a list of

3. The advantages

  • Simple and easy to use
  • Low coupling
  • No additional fields need to be added to the Bean
  • There is no callAdapter.notifyItemChangeMethod, so there is no flash screen Bug

Effect of three

Without further ado, above:

1. The radio

2. Choose more

4 use

1. The configuration

Start by adding the following configuration to your gradle file at the root of your project:

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io'}}}Copy the code

You can then add dependencies to your Moudle, or gradle file for your app:

implementation 'com. Making. Gminibird: CheckHelper: 1.0'
Copy the code

The last 1.0 is the version number, so go to GitHub to see the latest version and have fun.

2. Use

  • Create CheckHelper instance
    SingleCheckHelper mCheckHelper = new SingleCheckHelper();
    //or
    MultiCheckHelper mCheckHelper = new MultiCheckHelper();
    Copy the code
  • Register selector
    mCheckHelper.register(String.class, new CheckHelper.Checker<String, LwViewHolder>() @Override public void check(String s, LwViewHolder holder) {/ / selected state holder. ItemView. SetBackgroundColor (0 xff73e0e4); / / blue holder. SetChecked (R.i, dc heckbox,true); } @ Override public void unCheck (String s, LwViewHolder holder) {/ / not selected state holder. ItemView. SetBackgroundColor (0 XFFFFFFFF);  / / white holder. SetChecked (R.i, dc heckbox,false); }});Copy the code
  • Bind to Adapter
    @override protected void onBind(@nonnull LwViewHolder holder, @nonnull String item) { OnBindViewHolder McHeckhelper. bind(item, holder, holder.itemView); }Copy the code

And then, and then it’s done… Run to see the desired effect, and the selected data can be retrieved by calling getXXX() of the corresponding CheckHelper instance.

Five Implementation Principles

The general principle is very simple: the corresponding CheckHelper implementation class maintains some selected data internally. Here’s the implementation:

1. Template classCheckHelper

CheckHelper is the base of two implementation classes. It provides some basic common functions, such as setting up listeners, registering selectors, etc. It is a template pattern, which sets the common parts and the execution order, and then turns over to the subclass to complete the specific data increment.

There are two important methods, bind() and select(), which correspond to onBindViewHolder and 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)); / / comment 1 clickedView. SetOnClickListener (new View.OnClickListener() { @Override public void onClick(View view) { select(d, v); // Comment 2}}); }Copy the code

The bind() method that we bound to onBindViewHolder() will eventually call this method, starting with comment 1. The bind method in comment 1 makes a series of listener callbacks:

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); } onBindListenerbindListener = mOnBindListenerMap.get(d.getClass());
    if (bindListener ! = null) {bindListener.onBind(d, v, toCheck); }}Copy the code

There’s the Checker, which is the selector that we registered for unchecked and checked state is called, and then the OnCheckListener and the onBindListener, both of which we can add.

After calling a bunch of callbacks, it sets a listener for a view of the item. When clicked, it executes the select method, which also does a bunch of callbacks. So subclasses simply override these two methods and implement the corresponding data manipulation.

2. SingleCheckHelperThe radio

It’s easy, but here’s the tricky part:

How to cancel the last selection after selected?

As usual, we add an isChecked field to the Bean, select it with the current selection set to true, set the previous selection to false, and then call adapter to refresh.

I’m not relying on a Bean, but I can store information inside the ViewHolder, so I have the following code:

@Override
public void select(Object d, RecyclerView.ViewHolder v, boolean toCheck) {
    if(toCheck) { unCheckPre(d); / / comment 1setTag(v); // comment 2 this.v = v; this.d = d; }else {
        if(! canCancel){return; } clearTag(v); // Comment 3 this.d = null; this.v = null; } super.select(d, v, toCheck); }Copy the code

If it is selected and there is a tag, then the selected tag will be removed. If it is unselected, then the selected tag will be removed.

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) {// Set to nonselected if the previous selection exists and is visiblebind(d, v, false);
    }
}

private void setTag(RecyclerView.ViewHolder v) {
    if (v != null) {
        v.itemView.setTag(TAG, TAG_VALUE);
    }
}
Copy the code

It then calls back to the parent class’s set of callback interfaces.

3. MultiCheckHelper multi-select

Multi-selection classes mainly rely on a Map to maintain selected data, each data type corresponds to a Set, selected and unselected to call the corresponding method to update data, without great difficulty.

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()); }}}Copy the code

Due to the author’s limited level, if there is a better method welcome to discuss.

written by gminibird

Source code stamp above ^^^ ^

The authors introduce

  • Zeng Rongji: Android development engineer of Guangzhou Reed APP Team

Push the information

  • We are recruiting partners, interested partners can send your resume to [email protected], note: from the nuggets community
  • For details, please click here –> Guangzhou Reed Information Technology