package com.lin.poweradapter;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.annotation.IntDef;
import android.support.annotation.IntRange;
import android.support.v7.widget.RecyclerView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
*
* Created by lin18 on 2017/4/8.
*/
public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
private static final String TAG = "SelectableAdapter";
public static final int MODE_IDLE = 0, MODE_SINGLE = 1, MODE_MULTI = 2;
@IntDef({MODE_IDLE, MODE_SINGLE, MODE_MULTI})
@Retention(RetentionPolicy.SOURCE)
public @interface Mode {
}
@Mode
private int mMode;
private Set<Integer> mSelectedPositions;
public SelectableAdapter() {
mSelectedPositions = new TreeSet<>();
mMode = MODE_IDLE;
}
public void setMode(@Mode int mode) {
if (mMode == MODE_SINGLE && mode == MODE_IDLE)
clearSelection();
this.mMode = mode;
}
@Mode
public int getMode() {
return mMode;
}
public boolean isSelected(@IntRange(from = 0) int position) {
return mSelectedPositions.contains(position);
}
public abstract boolean isSelectable(@IntRange(from = 0) int position);
public void toggleSelection(@IntRange(from = 0) int position) {
if (position < 0) return;
if (mMode == MODE_SINGLE)
clearSelection();
boolean contains = mSelectedPositions.contains(position);
if (contains) {
removeSelection(position);
} else {
addSelection(position);
}
notifyItemChanged(position);
}
final boolean addAdjustedSelection(@IntRange(from = 0) int position) {
return mSelectedPositions.add(position);
}
public final boolean removeSelection(@IntRange(from = 0) int position) {
return mSelectedPositions.remove(position);
}
public final boolean addSelection(@IntRange(from = 0) int position) {
return isSelectable(position) && mSelectedPositions.add(position);
}
public void selectAll(Integer... viewTypes) {
List<Integer> viewTypesToSelect = Arrays.asList(viewTypes);
int positionStart = 0, itemCount = 0;
for (int i = 0; i < getItemCount(); i++) {
if (isSelectable(i) &&
(viewTypesToSelect.isEmpty() || viewTypesToSelect.contains(getItemViewType(i)))) {
mSelectedPositions.add(i);
itemCount++;
} else {
// Optimization for ItemRangeChanged
if (positionStart + itemCount == i) {
notifySelectionChanged(positionStart, itemCount);
itemCount = 0;
positionStart = i;
}
}
}
notifySelectionChanged(positionStart, getItemCount());
}
public void clearSelection() {
Iterator<Integer> iterator = mSelectedPositions.iterator();
int positionStart = 0, itemCount = 0;
// The notification is done only on items that are currently selected.
while (iterator.hasNext()) {
int position = iterator.next();
iterator.remove();
// Optimization for ItemRangeChanged
if (positionStart + itemCount == position) {
itemCount++;
} else {
// Notify previous items in range
notifySelectionChanged(positionStart, itemCount);
positionStart = position;
itemCount = 1;
}
}
// Notify remaining items in range
notifySelectionChanged(positionStart, itemCount);
}
private void notifySelectionChanged(int positionStart, int itemCount) {
if (itemCount > 0) {
notifyItemRangeChanged(positionStart, itemCount);
}
}
public int getSelectedItemCount() {
return mSelectedPositions.size();
}
public List<Integer> getSelectedPositions() {
return new ArrayList<>(mSelectedPositions);
}
public void onSaveInstanceState(Bundle outState) {
outState.putIntegerArrayList(TAG, new ArrayList<>(mSelectedPositions));
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
mSelectedPositions.addAll(savedInstanceState.getIntegerArrayList(TAG));
}
@CallSuper
@Override
public void onBindViewHolder(VH holder, int position) {
holder.itemView.setActivated(isSelected(position));
}
@Override
public void onViewRecycled(VH holder) {
super.onViewRecycled(holder);
}
@Override
public boolean onFailedToRecycleView(VH holder) {
return super.onFailedToRecycleView(holder);
}
@Override
public void onViewAttachedToWindow(VH holder) {
super.onViewAttachedToWindow(holder);
}
@Override
public void onViewDetachedFromWindow(VH holder) {
super.onViewDetachedFromWindow(holder);
}
}