package com.lin.poweradapter; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.support.v7.widget.RecyclerView; import com.lin.poweradapter.ParentExpandViewHolder.ParentViewHolderExpandCollapseListener; import com.lin.poweradapter.model.Parent; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * * Created by lin18 on 2017/4/24. */ public abstract class ExpandableAdapter<T, P extends Parent<C>, C, VH extends PowerViewHolder> extends MultiAdapter<T, VH> { @NonNull private List<RecyclerView> mAttachedRecyclerViewPool; @NonNull protected List<P> mAllItems; private Map<P, Boolean> mExpansionStateMap; @Nullable private ExpandCollapseListener mExpandCollapseListener; public ExpandableAdapter(@NonNull List<T> items) { super(items); init(items); } public ExpandableAdapter(@Nullable Object listener) { super(listener); init(new ArrayList<T>()); } public ExpandableAdapter(@Nullable Object listener, @NonNull List<T> items) { super(listener, items); init(items); } private void init(@NonNull List<T> items) { mAllItems = (List<P>) items; mAttachedRecyclerViewPool = new ArrayList<>(); mExpansionStateMap = new HashMap<>(items.size()); } @Override public void onBindVHolder(VH holder, int position) { super.onBindVHolder(holder, position); if (getItemViewType(position) != LOAD_MORE && getItemViewType(position) != HEADER && getItemViewType(position) != FOOTER) { bind(holder, position); } } @Override public void onBindViewHolder(VH holder, int position, List<Object> payloads) { if (getItemViewType(position) == LOAD_MORE) { } else if (getItemViewType(position) == HEADER) { } else if (getItemViewType(position) == FOOTER) { } else { bind(holder, position); delegatesManager.onBindViewHolder(getItem(position), position, holder, payloads); } } private void bind(@NonNull final VH holder, final int position) { if (holder instanceof ParentExpandViewHolder) { final ParentExpandViewHolder parentViewHolder = (ParentExpandViewHolder) holder; if (parentViewHolder.shouldItemViewClickToggleExpansion()) { parentViewHolder.setMainItemClickToExpand(); } parentViewHolder.mParent = (Parent) getItem(position); parentViewHolder.mExpandableAdapter = this; parentViewHolder.setParentViewHolderExpandCollapseListener(new ParentViewHolderExpandCollapseListener() { @Override public void onParentExpanded(final int flatParentPosition) { updateExpandedParent(flatParentPosition, true); } @Override public void onParentCollapsed(int flatParentPosition) { updateCollapsedParent(flatParentPosition, true); } }); } else if (holder instanceof ChildExpandViewHolder){ setListener(holder, position); final ChildExpandViewHolder childViewHolder = (ChildExpandViewHolder) holder; childViewHolder.mChild = getItem(position); childViewHolder.mExpandableAdapter = this; } } @Override @UiThread public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); if (mAttachedRecyclerViewPool != null && recyclerView != null) mAttachedRecyclerViewPool.add(recyclerView); } @Override @UiThread public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) { super.onDetachedFromRecyclerView(recyclerView); if (mAttachedRecyclerViewPool != null && recyclerView != null) mAttachedRecyclerViewPool.remove(recyclerView); } @UiThread public void setExpandCollapseListener(@Nullable ExpandCollapseListener expandCollapseListener) { mExpandCollapseListener = expandCollapseListener; } @UiThread private void updateExpandedParent(int position, boolean expansionTriggeredByListItemClick) { final P parent = (P) getItem(position); mExpansionStateMap.put(parent, true); final List<C> childList = parent.getChildList(); if (childList != null) { int childCount = childList.size(); for (int i = 0; i < childCount; i++) { getItems().add(position + i + 1, (T) childList.get(i)); } notifyItemRangeInserted(position + 1, childCount); } if (expansionTriggeredByListItemClick && mExpandCollapseListener != null) { mExpandCollapseListener.onParentExpanded(getNearestParentPosition(position)); } } @UiThread private void updateCollapsedParent(int position, boolean collapseTriggeredByListItemClick) { final P parent = (P) getItem(position); mExpansionStateMap.put(parent, false); final List<C> childList = parent.getChildList(); if (childList != null) { int childCount = childList.size(); for (int i = childCount - 1; i >= 0; i--) { getItems().remove(position + i + 1); } notifyItemRangeRemoved(position + 1, childCount); } if (collapseTriggeredByListItemClick && mExpandCollapseListener != null) { mExpandCollapseListener.onParentCollapsed(getNearestParentPosition(position)); } } @UiThread int getNearestParentPosition(int flatPosition) { if (flatPosition == 0) { return 0; } int parentCount = -1; for (int i = 0; i <= flatPosition; i++) { if (getItem(flatPosition) instanceof Parent) { parentCount++; } } return parentCount; } @UiThread int getChildPosition(@IntRange(from = 0) int flatPosition) { if (flatPosition == 0) { return 0; } int childCount = 0; for (int i = 0; i < flatPosition; i++) { if (!(getItem(flatPosition) instanceof Parent)) { childCount = 0; } else { childCount++; } } return childCount; } @UiThread public void expandParent(@NonNull P parent) { expandParent(mAllItems.indexOf(parent)); } @UiThread public void expandParent(int parentPosition) { if (parentPosition < 0 || parentPosition >= getItemCount()) return; expandViews(parentPosition); } @UiThread public void expandParentRange(int startParentPosition, int parentCount) { int endParentPosition = startParentPosition + parentCount; for (int i = startParentPosition; i < endParentPosition; i++) { expandParent(i); } } @UiThread public void expandAllParents() { for (P parent : mAllItems) { expandParent(parent); } } @UiThread private void expandViews(int position) { for (RecyclerView recyclerView : mAttachedRecyclerViewPool) { final VH holder = (VH) recyclerView.findViewHolderForAdapterPosition(position); if (holder != null && holder instanceof ParentExpandViewHolder) { final ParentExpandViewHolder viewHolder = (ParentExpandViewHolder) holder; if (!viewHolder.isExpanded()) { viewHolder.setExpanded(true); viewHolder.onExpansionToggled(false); } updateExpandedParent(position, false); } } } @UiThread public void collapseParent(@NonNull P parent) { collapseParent(mAllItems.indexOf(parent)); } @UiThread public void collapseParent(int parentPosition) { if (parentPosition < 0 || parentPosition >= getItemCount()) return; collapseParent(parentPosition); } @UiThread public void collapseParentRange(int startParentPosition, int parentCount) { int endParentPosition = startParentPosition + parentCount; for (int i = startParentPosition; i < endParentPosition; i++) { collapseParent(i); } } @UiThread public void collapseAllParents() { final int size = getItemCount(); for (int i = 0; i < size; i++) { collapseParent(i); } } @UiThread private void collapseViews(int position) { for (RecyclerView recyclerView : mAttachedRecyclerViewPool) { final VH holder = (VH) recyclerView.findViewHolderForAdapterPosition(position); if (holder != null && holder instanceof ParentExpandViewHolder) { final ParentExpandViewHolder viewHolder = (ParentExpandViewHolder) holder; if (viewHolder.isExpanded()) { viewHolder.setExpanded(false); viewHolder.onExpansionToggled(true); } updateExpandedParent(position, false); } } } public interface ExpandCollapseListener { @UiThread void onParentExpanded(int parentPosition); @UiThread void onParentCollapsed(int parentPosition); } }