package com.lcjian.lib.recyclerview;
|
|
import android.view.View;
|
import android.view.ViewGroup;
|
|
import androidx.annotation.NonNull;
|
import androidx.recyclerview.widget.GridLayoutManager;
|
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
|
import java.util.ArrayList;
|
import java.util.List;
|
|
public class AdvanceAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
|
private RecyclerView.Adapter<? extends RecyclerView.ViewHolder> mInnerAdapter;
|
private OnItemClickListener mOnItemClickListener;
|
private final List<Entry> headers;
|
private final List<Entry> footers;
|
private final RecyclerView.AdapterDataObserver dataObserver = new RecyclerView.AdapterDataObserver() {
|
@Override
|
public void onChanged() {
|
notifyDataSetChanged();
|
}
|
|
@Override
|
public void onItemRangeChanged(int positionStart, int itemCount) {
|
notifyItemRangeChanged(positionStart + headers.size(), itemCount);
|
}
|
|
@Override
|
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
|
notifyItemRangeChanged(positionStart + headers.size(), itemCount, payload);
|
}
|
|
@Override
|
public void onItemRangeInserted(int positionStart, int itemCount) {
|
notifyItemRangeInserted(positionStart + headers.size(), itemCount);
|
}
|
|
@Override
|
public void onItemRangeRemoved(int positionStart, int itemCount) {
|
notifyItemRangeRemoved(positionStart + headers.size(), itemCount);
|
}
|
|
@Override
|
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
|
int headCount = headers.size();
|
notifyItemRangeChanged(fromPosition + headCount, toPosition + headCount + itemCount);
|
}
|
};
|
|
public AdvanceAdapter(RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter) {
|
headers = new ArrayList<>();
|
footers = new ArrayList<>();
|
setInnerAdapter(adapter);
|
}
|
|
public void setInnerAdapter(RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter) {
|
if (mInnerAdapter != null) {
|
notifyItemRangeRemoved(headers.size(), mInnerAdapter.getItemCount());
|
mInnerAdapter.unregisterAdapterDataObserver(dataObserver);
|
}
|
|
this.mInnerAdapter = adapter;
|
mInnerAdapter.registerAdapterDataObserver(dataObserver);
|
notifyItemRangeInserted(headers.size(), mInnerAdapter.getItemCount());
|
}
|
|
public AdvanceAdapter setOnItemClickListener(OnItemClickListener onItemClickListener) {
|
this.mOnItemClickListener = onItemClickListener;
|
return this;
|
}
|
|
@Override
|
public int getItemCount() {
|
return headers.size() + footers.size() + mInnerAdapter.getItemCount();
|
}
|
|
@Override
|
public long getItemId(int position) {
|
int innerCount = mInnerAdapter.getItemCount();
|
int headCount = headers.size();
|
if (position < headCount) {
|
return headers.get(position).viewType;
|
} else if (position < headCount + innerCount) {
|
return mInnerAdapter.getItemId(position - headCount);
|
} else {
|
return footers.get(position - headCount - innerCount).viewType;
|
}
|
}
|
|
@Override
|
public int getItemViewType(int position) {
|
int innerCount = mInnerAdapter.getItemCount();
|
int headCount = headers.size();
|
if (position < headCount) {
|
return headers.get(position).viewType;
|
} else if (position < headCount + innerCount) {
|
return mInnerAdapter.getItemViewType(position - headCount);
|
} else {
|
return footers.get(position - headCount - innerCount).viewType;
|
}
|
}
|
|
@NonNull
|
@Override
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
for (Entry header : headers) {
|
if (header.viewType == viewType) {
|
return new AdvanceHolder(header.view, header);
|
}
|
}
|
for (Entry footer : footers) {
|
if (footer.viewType == viewType) {
|
return new AdvanceHolder(footer.view, footer);
|
}
|
}
|
RecyclerView.ViewHolder holder = mInnerAdapter.onCreateViewHolder(parent, viewType);
|
if (mOnItemClickListener != null) {
|
holder.itemView.setOnClickListener(itemView -> mOnItemClickListener.onItemClick(itemView));
|
}
|
return holder;
|
}
|
|
@Override
|
@SuppressWarnings("unchecked")
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
if (!(holder instanceof AdvanceHolder)) {
|
((RecyclerView.Adapter<RecyclerView.ViewHolder>) mInnerAdapter).onBindViewHolder(holder, position - headers.size());
|
}
|
}
|
|
@Override
|
@SuppressWarnings("unchecked")
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
|
if (!(holder instanceof AdvanceHolder)) {
|
((RecyclerView.Adapter<RecyclerView.ViewHolder>) mInnerAdapter).onBindViewHolder(holder, position - headers.size(), payloads);
|
}
|
}
|
|
@Override
|
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
|
mInnerAdapter.onAttachedToRecyclerView(recyclerView);
|
|
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
|
if (layoutManager instanceof GridLayoutManager) {
|
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
|
final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup();
|
|
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
|
@Override
|
public int getSpanSize(int position) {
|
if (isSingle(position)) {
|
return gridLayoutManager.getSpanCount();
|
} else {
|
if (spanSizeLookup != null) {
|
return spanSizeLookup.getSpanSize(position);
|
}
|
}
|
return 1;
|
}
|
});
|
gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount());
|
}
|
}
|
|
@Override
|
@SuppressWarnings("unchecked")
|
public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) {
|
if (holder instanceof AdvanceHolder) {
|
if (((AdvanceHolder) holder).entry.singleLine) {
|
ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
|
|
if (layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
|
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) layoutParams;
|
p.setFullSpan(true);
|
}
|
}
|
} else {
|
((RecyclerView.Adapter<RecyclerView.ViewHolder>) mInnerAdapter).onViewAttachedToWindow(holder);
|
}
|
}
|
|
@Override
|
@SuppressWarnings("unchecked")
|
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
|
if (holder instanceof AdvanceHolder) {
|
super.onViewRecycled(holder);
|
} else {
|
((RecyclerView.Adapter<RecyclerView.ViewHolder>) mInnerAdapter).onViewRecycled(holder);
|
}
|
}
|
|
@Override
|
@SuppressWarnings("unchecked")
|
public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) {
|
if (holder instanceof AdvanceHolder) {
|
super.onViewDetachedFromWindow(holder);
|
} else {
|
((RecyclerView.Adapter<RecyclerView.ViewHolder>) mInnerAdapter).onViewDetachedFromWindow(holder);
|
}
|
}
|
|
@Override
|
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
|
mInnerAdapter.onDetachedFromRecyclerView(recyclerView);
|
}
|
|
@Override
|
@SuppressWarnings("unchecked")
|
public boolean onFailedToRecycleView(@NonNull RecyclerView.ViewHolder holder) {
|
if (holder instanceof AdvanceHolder) {
|
return super.onFailedToRecycleView(holder);
|
} else {
|
return ((RecyclerView.Adapter<RecyclerView.ViewHolder>) mInnerAdapter).onFailedToRecycleView(holder);
|
}
|
}
|
|
private boolean isHeader(int position) {
|
return position < headers.size();
|
}
|
|
private boolean isFooter(int position) {
|
return headers.size() + mInnerAdapter.getItemCount() <= position;
|
}
|
|
private boolean isSingle(int position) {
|
return (isHeader(position) && headers.get(position).singleLine)
|
|| (isFooter(position) && footers.get(position - headers.size() - mInnerAdapter.getItemCount()).singleLine);
|
}
|
|
public void addHeader(View view) {
|
addHeader(view, true);
|
}
|
|
public void addHeader(View view, boolean singleLine) {
|
addHeader(headers.size(), view, singleLine);
|
}
|
|
public void addHeader(int location, View view, boolean singleLine) {
|
|
for (Entry header : headers) {
|
if (header.view == view) {
|
return;
|
}
|
}
|
// FIXME may conflict with this inner adapter
|
headers.add(location, new Entry(view, view.hashCode(), singleLine));
|
notifyItemInserted(location);
|
}
|
|
public void removeHeader(View view) {
|
if (view == null) {
|
return;
|
}
|
int i = 0;
|
for (Entry header : headers) {
|
if (header.view == view) {
|
headers.remove(header);
|
notifyItemRemoved(i);
|
break;
|
}
|
i++;
|
}
|
}
|
|
public void addFooter(View view) {
|
addFooter(view, true);
|
}
|
|
public void addFooter(View view, boolean singleLine) {
|
addFooter(footers.size(), view, singleLine);
|
}
|
|
public void addFooter(int location, View view, boolean singleLine) {
|
if (view == null) {
|
return;
|
}
|
for (Entry footer : footers) {
|
if (footer.view == view) {
|
return;
|
}
|
}
|
// FIXME may conflict with this inner adapter
|
footers.add(location, new Entry(view, view.hashCode(), singleLine));
|
notifyItemInserted(headers.size() + mInnerAdapter.getItemCount() + location);
|
}
|
|
public void removeFooter(View view) {
|
if (view == null) {
|
return;
|
}
|
int i = 0;
|
for (Entry footer : footers) {
|
if (footer.view == view) {
|
footers.remove(footer);
|
notifyItemRemoved(headers.size() + mInnerAdapter.getItemCount() + i);
|
break;
|
}
|
i++;
|
}
|
}
|
|
public interface OnItemClickListener {
|
|
void onItemClick(View itemView);
|
}
|
|
private static class AdvanceHolder extends RecyclerView.ViewHolder {
|
|
private final Entry entry;
|
|
private AdvanceHolder(View itemView, Entry entry) {
|
super(itemView);
|
this.entry = entry;
|
}
|
}
|
|
private static class Entry {
|
View view;
|
int viewType;
|
boolean singleLine;
|
|
private Entry(View view, int viewType, boolean singleLine) {
|
this.view = view;
|
this.viewType = viewType;
|
this.singleLine = singleLine;
|
}
|
}
|
}
|