package com.lzx.demo.base;
import android.content.Context;
import android.support.annotation.IntRange;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.lzx.demo.bean.MultiItemEntity;
import com.lzx.demo.bean.Person;
import com.lzx.demo.interfaces.IExpandable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public abstract class BaseMultiAdapter<T extends MultiItemEntity> extends RecyclerView.Adapter<SuperViewHolder> {
protected Context mContext;
private LayoutInflater mInflater;
/**
* layouts indexed with their types
*/
private SparseArray<Integer> layouts;
private static final int DEFAULT_VIEW_TYPE = -0xff;
protected List<T> mDataList = new ArrayList<>();
public BaseMultiAdapter(Context context) {
mContext = context;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getItemViewType(int position) {
Object item = mDataList.get(position);
if (item instanceof MultiItemEntity) {
return ((MultiItemEntity)item).getItemType();
}
return DEFAULT_VIEW_TYPE;
}
@Override
public SuperViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = mInflater.inflate(getLayoutId(viewType), parent, false);
return new SuperViewHolder(itemView);
}
@Override
public void onBindViewHolder(SuperViewHolder holder, int position) {
onBindItemHolder(holder, position);
}
//局部刷新关键:带payload的这个onBindViewHolder方法必须实现
@Override
public void onBindViewHolder(SuperViewHolder holder, int position, List<Object> payloads) {
if (payloads.isEmpty()) {
onBindItemHolder(holder, position);
} else {
onBindItemHolder(holder, position, payloads);
}
}
//根据ViewType获取LayoutId
public int getLayoutId(int viewType) {
return layouts.get(viewType);
}
protected void addItemType(int type, @LayoutRes int layoutResId) {
if (layouts == null) {
layouts = new SparseArray<>();
}
layouts.put(type, layoutResId);
}
public abstract void onBindItemHolder(SuperViewHolder holder, int position);
public void onBindItemHolder(SuperViewHolder holder, int position, List<Object> payloads){
}
@Override
public int getItemCount() {
return mDataList.size();
}
public List<T> getDataList() {
return mDataList;
}
public void setDataList(Collection<T> list) {
this.mDataList.clear();
this.mDataList.addAll(list);
notifyDataSetChanged();
}
public void addAll(Collection<T> list) {
int lastIndex = this.mDataList.size();
if (this.mDataList.addAll(list)) {
notifyItemRangeInserted(lastIndex, list.size());
}
}
public void remove(int position) {
this.mDataList.remove(position);
notifyItemRemoved(position);
if(position != (getDataList().size())){ // 如果移除的是最后一个,忽略
notifyItemRangeChanged(position,this.mDataList.size()-position);
}
}
public void clear() {
mDataList.clear();
notifyDataSetChanged();
}
/**
* Expand an expandable item
*
* @param position position of the item
* @param animate expand items with animation
* @param shouldNotify notify the RecyclerView to rebind items, <strong>false</strong> if you want to do it yourself.
* @return the number of items that have been added.
*/
public int expand(@IntRange(from = 0) int position, boolean animate, boolean shouldNotify) {
position -= getHeaderLayoutCount();
IExpandable expandable = getExpandableItem(position);
if (expandable == null) {
return 0;
}
if (!hasSubItems(expandable)) {
expandable.setExpanded(false);
return 0;
}
int subItemCount = 0;
if (!expandable.isExpanded()) {
List list = expandable.getSubItems();
mDataList.addAll(position + 1, list);
subItemCount += recursiveExpand(position + 1, list);
expandable.setExpanded(true);
subItemCount += list.size();
}
int parentPos = position + getHeaderLayoutCount();
if (shouldNotify) {
if (animate) {
notifyItemChanged(parentPos);
notifyItemRangeInserted(parentPos + 1, subItemCount);
} else {
notifyDataSetChanged();
}
}
return subItemCount;
}
/**
* Expand an expandable item
*
* @param position position of the item, which includes the header layout count.
* @param animate expand items with animation
* @return the number of items that have been added.
*/
public int expand(@IntRange(from = 0) int position, boolean animate) {
return expand(position, animate, true);
}
/**
* Expand an expandable item with animation.
*
* @param position position of the item, which includes the header layout count.
* @return the number of items that have been added.
*/
public int expand(@IntRange(from = 0) int position) {
return expand(position, true, true);
}
public int expandAll(int position, boolean animate, boolean notify) {
position -= getHeaderLayoutCount();
T endItem = null;
if (position + 1 < this.mDataList.size()) {
endItem = getItem(position + 1);
}
IExpandable expandable = getExpandableItem(position);
if (!hasSubItems(expandable)) {
return 0;
}
int count = expand(position + getHeaderLayoutCount(), false, false);
for (int i = position + 1; i < this.mDataList.size(); i++) {
T item = getItem(i);
if (item == endItem) {
break;
}
if (isExpandable(item)) {
count += expand(i + getHeaderLayoutCount(), false, false);
}
}
if (notify) {
if (animate) {
notifyItemRangeInserted(position + getHeaderLayoutCount() + 1, count);
} else {
notifyDataSetChanged();
}
}
return count;
}
/**
* expand the item and all its subItems
*
* @param position position of the item, which includes the header layout count.
* @param init whether you are initializing the recyclerView or not.
* if <strong>true</strong>, it won't notify recyclerView to redraw UI.
* @return the number of items that have been added to the adapter.
*/
public int expandAll(int position, boolean init) {
return expandAll(position, true, !init);
}
private int recursiveCollapse(@IntRange(from = 0) int position) {
T item = getItem(position);
if (!isExpandable(item)) {
return 0;
}
IExpandable expandable = (IExpandable) item;
int subItemCount = 0;
if (expandable.isExpanded()) {
List<T> subItems = expandable.getSubItems();
for (int i = subItems.size() - 1; i >= 0; i--) {
T subItem = subItems.get(i);
int pos = getItemPosition(subItem);
if (pos < 0) {
continue;
}
if (subItem instanceof IExpandable) {
subItemCount += recursiveCollapse(pos);
}
mDataList.remove(pos);
subItemCount++;
}
}
return subItemCount;
}
private int recursiveExpand(int position, @NonNull List list) {
int count = 0;
int pos = position + list.size() - 1;
for (int i = list.size() - 1; i >= 0; i--, pos--) {
if (list.get(i) instanceof IExpandable) {
IExpandable item = (IExpandable) list.get(i);
if (item.isExpanded() && hasSubItems(item)) {
List subList = item.getSubItems();
mDataList.addAll(pos + 1, subList);
int subItemCount = recursiveExpand(pos + 1, subList);
count += subItemCount;
}
}
}
return count;
}
private boolean hasSubItems(IExpandable item) {
List list = item.getSubItems();
return list != null && list.size() > 0;
}
private boolean isExpandable(T item) {
return item != null && item instanceof IExpandable;
}
private IExpandable getExpandableItem(int position) {
T item = getItem(position);
if (isExpandable(item)) {
return (IExpandable) item;
} else {
return null;
}
}
/**
* Collapse an expandable item that has been expanded..
*
* @param position the position of the item, which includes the header layout count.
* @param animate collapse with animation or not.
* @param notify notify the recyclerView refresh UI or not.
* @return the number of subItems collapsed.
*/
public int collapse(@IntRange(from = 0) int position, boolean animate, boolean notify) {
position -= getHeaderLayoutCount();
IExpandable expandable = getExpandableItem(position);
if (expandable == null) {
return 0;
}
int subItemCount = recursiveCollapse(position);
expandable.setExpanded(false);
int parentPos = position + getHeaderLayoutCount();
if (notify) {
if (animate) {
notifyItemChanged(parentPos);
notifyItemRangeRemoved(parentPos + 1, subItemCount);
} else {
notifyDataSetChanged();
}
}
return subItemCount;
}
/**
* Collapse an expandable item that has been expanded..
*
* @param position the position of the item, which includes the header layout count.
* @return the number of subItems collapsed.
*/
public int collapse(@IntRange(from = 0) int position) {
return collapse(position, true, true);
}
/**
* Collapse an expandable item that has been expanded..
*
* @param position the position of the item, which includes the header layout count.
* @return the number of subItems collapsed.
*/
public int collapse(@IntRange(from = 0) int position, boolean animate) {
return collapse(position, animate, true);
}
private int getItemPosition(T item) {
return item != null && mDataList != null && !mDataList.isEmpty() ? mDataList.indexOf(item) : -1;
}
/**
* Get the data item associated with the specified position in the data set.
*
* @param position Position of the item whose data we want within the adapter's
* data set.
* @return The data at the specified position.
*/
public T getItem(int position) {
return mDataList.get(position);
}
/**
* if addHeaderView will be return 1, if not will be return 0
*/
public int getHeaderLayoutCount() {
return 0;
}
}