package com.android.app_base.widget; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import androidx.annotation.LayoutRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.List; /** * 支持添加底部和头部的 RecyclerView */ public final class WrapRecyclerView extends RecyclerView { /** * 原有的适配器 */ private Adapter mRealAdapter; /** * 支持添加头部和底部的适配器 */ private final WrapRecyclerAdapter mWrapAdapter = new WrapRecyclerAdapter(); public WrapRecyclerView(Context context) { super(context); } public WrapRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public WrapRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void setAdapter(Adapter adapter) { mRealAdapter = adapter; // 偷梁换柱 mWrapAdapter.setRealAdapter(mRealAdapter); // 禁用条目动画 setItemAnimator(null); super.setAdapter(mWrapAdapter); } @Override public Adapter getAdapter() { return mRealAdapter; } /** * 添加头部View */ public void addHeaderView(View view) { mWrapAdapter.addHeaderView(view); } @SuppressWarnings("unchecked") public V addHeaderView(@LayoutRes int id) { View headerView = LayoutInflater.from(getContext()).inflate(id, this, false); addHeaderView(headerView); return (V) headerView; } /** * 移除头部View */ public void removeHeaderView(View view) { mWrapAdapter.removeHeaderView(view); } /** * 添加底部View */ public void addFooterView(View view) { mWrapAdapter.addFooterView(view); } @SuppressWarnings("unchecked") public V addFooterView(@LayoutRes int id) { View footerView = LayoutInflater.from(getContext()).inflate(id, this, false); addFooterView(footerView); return (V) footerView; } /** * 移除底部View */ public void removeFooterView(View view) { mWrapAdapter.removeFooterView(view); } /** * 获取头部View总数 */ public int getHeaderViewsCount() { return mWrapAdapter.getHeaderViewsCount(); } /** * 获取底部View总数 */ public int getFooterViewsCount() { return mWrapAdapter.getFooterViewsCount(); } /** * 获取头部View集合 */ public List getHeaderViews() { return mWrapAdapter.getHeaderViews(); } /** * 获取底部View集合 */ public List getFooterViews() { return mWrapAdapter.getFooterViews(); } /** * 刷新头部和底部布局所有的 View 的状态 */ public void refreshHeaderFooterViews() { mWrapAdapter.notifyDataSetChanged(); } /** * 设置在 GridLayoutManager 模式下头部和尾部都是独占一行的效果 */ public void adjustSpanSize() { final LayoutManager layoutManager = getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { ((GridLayoutManager) layoutManager).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { return (position < mWrapAdapter.getHeaderViewsCount() || position >= mWrapAdapter.getHeaderViewsCount() + (mRealAdapter == null ? 0 : mRealAdapter.getItemCount())) ? ((GridLayoutManager) layoutManager).getSpanCount() : 1; } }); } } /** * 采用装饰设计模式,将原有的适配器包装起来 */ private static final class WrapRecyclerAdapter extends Adapter { /** * 头部条目类型 */ private static final int HEADER_VIEW_TYPE = Integer.MIN_VALUE >> 1; /** * 底部条目类型 */ private static final int FOOTER_VIEW_TYPE = Integer.MAX_VALUE >> 1; /** * 原有的适配器 */ private Adapter mRealAdapter; /** * 头部View集合 */ private final List mHeaderViews = new ArrayList<>(); /** * 底部View集合 */ private final List mFooterViews = new ArrayList<>(); /** * 当前调用的位置 */ private int mCurrentPosition; /** * RecyclerView对象 */ private RecyclerView mRecyclerView; /** * 数据观察者对象 */ private WrapAdapterDataObserver mObserver; private void setRealAdapter(Adapter adapter) { if (mRealAdapter != adapter) { if (mRealAdapter != null) { if (mObserver != null) { // 为原有的RecyclerAdapter移除数据监听对象 mRealAdapter.unregisterAdapterDataObserver(mObserver); } } mRealAdapter = adapter; if (mRealAdapter != null) { if (mObserver == null) { mObserver = new WrapAdapterDataObserver(this); } // 为原有的RecyclerAdapter添加数据监听对象 mRealAdapter.registerAdapterDataObserver(mObserver); // 适配器不是第一次被绑定到RecyclerView上需要发送通知,因为第一次绑定会自动通知 if (mRecyclerView != null) { notifyDataSetChanged(); } } } } @Override public int getItemCount() { if (mRealAdapter != null) { return getHeaderViewsCount() + mRealAdapter.getItemCount() + getFooterViewsCount(); } else { return getHeaderViewsCount() + getFooterViewsCount(); } } @SuppressWarnings("all") @Override public int getItemViewType(int position) { mCurrentPosition = position; // 获取头部布局的总数 int headerCount = getHeaderViewsCount(); // 获取原有适配器的总数 int adapterCount = mRealAdapter != null ? mRealAdapter.getItemCount() : 0; // 获取在原有适配器上的位置 int adjPosition = position - headerCount; if (position < headerCount) { return HEADER_VIEW_TYPE; } else if (adjPosition < adapterCount) { return mRealAdapter.getItemViewType(adjPosition); } else { return FOOTER_VIEW_TYPE; } } public int getPosition() { return mCurrentPosition; } @SuppressWarnings("all") @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { switch (viewType) { case HEADER_VIEW_TYPE: return newWrapViewHolder(mHeaderViews.get(getPosition())); case FOOTER_VIEW_TYPE: return newWrapViewHolder(mFooterViews.get(getPosition() - getHeaderViewsCount() - (mRealAdapter != null ? mRealAdapter.getItemCount() : 0))); default: int itemViewType = mRealAdapter.getItemViewType(getPosition() - getHeaderViewsCount()); if (itemViewType == HEADER_VIEW_TYPE || itemViewType == FOOTER_VIEW_TYPE) { throw new IllegalStateException("Please do not use this type as itemType"); } if (mRealAdapter != null) { return mRealAdapter.onCreateViewHolder(parent, itemViewType); } else { return null; } } } @SuppressWarnings("unchecked") @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { int viewType = getItemViewType(position); switch (viewType) { case HEADER_VIEW_TYPE: case FOOTER_VIEW_TYPE: break; default: if (mRealAdapter != null) { mRealAdapter.onBindViewHolder(holder, getPosition() - getHeaderViewsCount()); } break; } } private WrapViewHolder newWrapViewHolder(View view) { ViewParent parent = view.getParent(); if (parent instanceof ViewGroup) { // IllegalStateException: ViewHolder views must not be attached when created. // Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot) ((ViewGroup) parent).removeView(view); } return new WrapViewHolder(view); } @Override public long getItemId(int position) { if (mRealAdapter != null && position > getHeaderViewsCount() - 1 && position < getHeaderViewsCount() + mRealAdapter.getItemCount()) { return mRealAdapter.getItemId(position - getHeaderViewsCount()); } else { return super.getItemId(position); } } @Override public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { mRecyclerView = recyclerView; if (mRealAdapter != null) { mRealAdapter.onAttachedToRecyclerView(recyclerView); } } @Override public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) { mRecyclerView = null; if (mRealAdapter != null) { mRealAdapter.onDetachedFromRecyclerView(recyclerView); } } @SuppressWarnings("unchecked") @Override public void onViewRecycled(@NonNull ViewHolder holder) { if (holder instanceof WrapViewHolder) { // 防止这个 ViewHolder 被 RecyclerView 拿去复用 holder.setIsRecyclable(false); return; } if (mRealAdapter != null) { mRealAdapter.onViewRecycled(holder); } } @SuppressWarnings("unchecked") @Override public boolean onFailedToRecycleView(@NonNull ViewHolder holder) { if (mRealAdapter != null) { return mRealAdapter.onFailedToRecycleView(holder); } return super.onFailedToRecycleView(holder); } @SuppressWarnings("unchecked") @Override public void onViewAttachedToWindow(@NonNull ViewHolder holder) { if (mRealAdapter != null) { mRealAdapter.onViewAttachedToWindow(holder); } } @SuppressWarnings("unchecked") @Override public void onViewDetachedFromWindow(@NonNull ViewHolder holder) { if (mRealAdapter != null) { mRealAdapter.onViewDetachedFromWindow(holder); } } /** * 添加头部View */ private void addHeaderView(View view) { // 不能添加同一个View对象,否则会导致RecyclerView复用异常 if (!mHeaderViews.contains(view) && !mFooterViews.contains(view)) { mHeaderViews.add(view); notifyDataSetChanged(); } } /** * 移除头部View */ private void removeHeaderView(View view) { if (mHeaderViews.remove(view)) { notifyDataSetChanged(); } } /** * 添加底部View */ private void addFooterView(View view) { // 不能添加同一个View对象,否则会导致RecyclerView复用异常 if (!mFooterViews.contains(view) && !mHeaderViews.contains(view)) { mFooterViews.add(view); notifyDataSetChanged(); } } /** * 移除底部View */ private void removeFooterView(View view) { if (mFooterViews.remove(view)) { notifyDataSetChanged(); } } /** * 获取头部View总数 */ private int getHeaderViewsCount() { return mHeaderViews.size(); } /** * 获取底部View总数 */ private int getFooterViewsCount() { return mFooterViews.size(); } /** * 获取头部View集合 */ private List getHeaderViews() { return mHeaderViews; } /** * 获取底部View集合 */ private List getFooterViews() { return mFooterViews; } } /** * 头部和底部通用的ViewHolder对象 */ private static final class WrapViewHolder extends ViewHolder { private WrapViewHolder(View itemView) { super(itemView); } } /** * 数据改变监听器 */ private static final class WrapAdapterDataObserver extends AdapterDataObserver { private final WrapRecyclerAdapter mWrapAdapter; private WrapAdapterDataObserver(WrapRecyclerAdapter adapter) { mWrapAdapter = adapter; } @Override public void onChanged() { mWrapAdapter.notifyDataSetChanged(); } @Override public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { onItemRangeChanged(mWrapAdapter.getHeaderViewsCount() + positionStart, itemCount); } @Override public void onItemRangeChanged(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeChanged(mWrapAdapter.getHeaderViewsCount() + positionStart, itemCount); } @Override public void onItemRangeInserted(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeInserted(mWrapAdapter.getHeaderViewsCount() + positionStart, itemCount); } @Override public void onItemRangeRemoved(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeRemoved(mWrapAdapter.getHeaderViewsCount() + positionStart, itemCount); } @Override public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { mWrapAdapter.notifyItemMoved(mWrapAdapter.getHeaderViewsCount() + fromPosition, toPosition); } } }