RecyclerView–添加头部和底部详解手机开发

1.先构建WrapRecyclerAdapter

/** 
 * Description: 可以添加头部和底部的Adapter 
 */   
public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { 
    private final static String TAG = "WrapRecyclerAdapter"; 
   
    /** 
     * SparseArrays map integers to Objects.  Unlike a normal array of Objects, 
     * there can be gaps in the indices.  It is intended to be more memory efficient 
     * than using a HashMap to map Integers to Objects, both because it avoids 
     * auto-boxing keys and its data structure doesn't rely on an extra entry object 
     * for each mapping. 
     * 
     * SparseArray是一个<int , Object>的HashMap  比HashMap更高效 
     */  
    private SparseArray<View> mHeaderViews; 
    private SparseArray<View> mFooterViews; 
  
    // 基本的头部类型开始位置  用于viewType  
    private static int BASE_ITEM_TYPE_HEADER = 10000000; 
    // 基本的底部类型开始位置  用于viewType  
    private static int BASE_ITEM_TYPE_FOOTER = 20000000; 
  
    /** 
     * 数据列表的Adapter 
     */  
    private RecyclerView.Adapter mAdapter; 
  
    public WrapRecyclerAdapter(RecyclerView.Adapter adapter) { 
        this.mAdapter = adapter; 
        mHeaderViews = new SparseArray<>(); 
        mFooterViews = new SparseArray<>(); 
    } 
  
    @Override 
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
  
        // viewType 可能就是 SparseArray 的key  
        if (isHeaderViewType(viewType)) { 
            View headerView = mHeaderViews.get(viewType); 
            return createHeaderFooterViewHolder(headerView); 
        } 
  
        if (isFooterViewType(viewType)) { 
            View footerView = mFooterViews.get(viewType); 
            return createHeaderFooterViewHolder(footerView); 
        } 
        return mAdapter.onCreateViewHolder(parent, viewType); 
    } 
  
    /** 
     * 是不是底部类型 
     */  
    private boolean isFooterViewType(int viewType) { 
        int position = mFooterViews.indexOfKey(viewType); 
        return position >= 0; 
    } 
  
    /** 
     * 创建头部或者底部的ViewHolder 
     */  
    private RecyclerView.ViewHolder createHeaderFooterViewHolder(View view) { 
        return new RecyclerView.ViewHolder(view) { 
  
        }; 
    } 
  
    /** 
     * 是不是头部类型 
     */  
    private boolean isHeaderViewType(int viewType) { 
        int position = mHeaderViews.indexOfKey(viewType); 
        return position >= 0; 
    } 
  
    @Override 
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 
        if (isHeaderPosition(position) || isFooterPosition(position)) { 
            return; 
        } 
  
        // 计算一下位置  
        final int adapterPosition = position - mHeaderViews.size(); 
        mAdapter.onBindViewHolder(holder, adapterPosition); 
  
        // 设置点击和长按事件  
        if (mItemClickListener != null) { 
            holder.itemView.setOnClickListener(new View.OnClickListener() { 
                @Override 
                public void onClick(View v) { 
                    mItemClickListener.onItemClick(v, adapterPosition); 
                } 
            }); 
        } 
        if (mLongClickListener != null) { 
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { 
                @Override 
                public boolean onLongClick(View v) { 
                    return mLongClickListener.onLongClick(v, adapterPosition); 
                } 
            }); 
        } 
    } 
 
    @Override 
    public int getItemViewType(int position) { 
        if (isHeaderPosition(position)) { 
            // 直接返回position位置的key 
            return mHeaderViews.keyAt(position); 
        } 
        if (isFooterPosition(position)) { 
            // 直接返回position位置的key 
            position = position - mHeaderViews.size() - mAdapter.getItemCount(); 
            return mFooterViews.keyAt(position); 
        } 
        // 返回列表Adapter的getItemViewType 117         position = position - mHeaderViews.size(); 
        return mAdapter.getItemViewType(position); 
    } 
 
    /** 
     * 是不是底部位置 
     */ 
    private boolean isFooterPosition(int position) { 
        return position >= (mHeaderViews.size() + mAdapter.getItemCount()); 
    } 
 
    /** 
     * 是不是头部位置 
     */ 
    private boolean isHeaderPosition(int position) { 
        return position < mHeaderViews.size(); 
    } 
 
    @Override 
    public int getItemCount() { 
        // 条数三者相加 = 底部条数 + 头部条数 + Adapter的条数 
        return mAdapter.getItemCount() + mHeaderViews.size() + mFooterViews.size(); 
    } 
 
    /** 
     * 获取列表的Adapter 
     */ 
    private RecyclerView.Adapter getAdapter() { 
        return mAdapter; 
    } 
 
    // 添加头部 
    public void addHeaderView(View view) { 
        int position = mHeaderViews.indexOfValue(view); 
        if (position < 0) { 
            mHeaderViews.put(BASE_ITEM_TYPE_HEADER++, view); 
        } 
        notifyDataSetChanged(); 
    } 
 
    // 添加底部 
    public void addFooterView(View view) { 
        int position = mFooterViews.indexOfValue(view); 
        if (position < 0) { 
            mFooterViews.put(BASE_ITEM_TYPE_FOOTER++, view); 
        } 
        notifyDataSetChanged(); 
    } 
 
    // 移除头部 
    public void removeHeaderView(View view) { 
        int index = mHeaderViews.indexOfValue(view); 
        if (index < 0) return; 
        mHeaderViews.removeAt(index); 
        notifyDataSetChanged(); 
    } 
 
    // 移除底部 
    public void removeFooterView(View view) { 
        int index = mFooterViews.indexOfValue(view); 
        if (index < 0) return; 
        mFooterViews.removeAt(index); 
        notifyDataSetChanged(); 
    } 
 
    /** 
     * 解决GridLayoutManager添加头部和底部不占用一行的问题 
     * 
     * @param recycler 
     * @version 1.0 
     */ 
    public void adjustSpanSize(RecyclerView recycler) { 
        if (recycler.getLayoutManager() instanceof GridLayoutManager) { 
            final GridLayoutManager layoutManager = (GridLayoutManager) recycler.getLayoutManager(); 
            layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 
                @Override 
                public int getSpanSize(int position) { 
                    boolean isHeaderOrFooter = 
                            isHeaderPosition(position) || isFooterPosition(position); 
                    return isHeaderOrFooter ? layoutManager.getSpanCount() : 1; 
                } 
            }); 
        } 
    } 
 
    /*************** 
     * 给条目设置点击和长按事件 
     *********************/ 205     public OnItemClickListener mItemClickListener; 
    public OnLongClickListener mLongClickListener; 
 
    public void setOnItemClickListener(OnItemClickListener itemClickListener) { 
        this.mItemClickListener = itemClickListener; 
    } 
 
    public void setOnLongClickListener(OnLongClickListener longClickListener) { 
        this.mLongClickListener = longClickListener; 
    } 
}

2.构建WrapRecyclerView

我们最好还是模仿ListView的结构搞就搞到西,自定义一个WrapRecyclerView,可以添加删除头部和底部View,这个就比较简单

/** 
 * Description: 可以添加头部和底部的RecyclerView 
 */   
public class WrapRecyclerView extends RecyclerView { 
    // 包裹了一层的头部底部Adapter   
    private WrapRecyclerAdapter mWrapRecyclerAdapter; 
    // 这个是列表数据的Adapter   
    private Adapter mAdapter; 
  
     // 增加一些通用功能 
    // 空列表数据应该显示的空View 
    // 正在加载数据页面,也就是正在获取后台接口页面  
    private View mEmptyView, mLoadingView; 
  
    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) { 
        // 为了防止多次设置Adapter  
        if (mAdapter != null) { 
            mAdapter.unregisterAdapterDataObserver(mDataObserver); 
            mAdapter = null; 
        } 
  
        this.mAdapter = adapter; 
  
        if (adapter instanceof WrapRecyclerAdapter) { 
            mWrapRecyclerAdapter = (WrapRecyclerAdapter) adapter; 
        } else { 
            mWrapRecyclerAdapter = new WrapRecyclerAdapter(adapter); 
        } 
  
        super.setAdapter(mWrapRecyclerAdapter); 
  
        // 注册一个观察者  
        mAdapter.registerAdapterDataObserver(mDataObserver); 
  
        // 解决GridLayout添加头部和底部也要占据一行  
        mWrapRecyclerAdapter.adjustSpanSize(this); 
  
        // 加载数据页面  
        if (mLoadingView != null && mLoadingView.getVisibility() == View.VISIBLE) { 
            mLoadingView.setVisibility(View.GONE); 
        } 
  
        if (mItemClickListener != null) { 
            mWrapRecyclerAdapter.setOnItemClickListener(mItemClickListener); 
        } 
  
        if (mLongClickListener != null) { 
            mWrapRecyclerAdapter.setOnLongClickListener(mLongClickListener); 
        } 
    } 
  
    // 添加头部  
    public void addHeaderView(View view) { 
        // 如果没有Adapter那么就不添加,也可以选择抛异常提示 
        // 让他必须先设置Adapter然后才能添加,这里是仿照ListView的处理方式  
        if (mWrapRecyclerAdapter != null) { 
            mWrapRecyclerAdapter.addHeaderView(view); 
        } 
    } 
  
    // 添加底部  
    public void addFooterView(View view) { 
        if (mWrapRecyclerAdapter != null) { 
            mWrapRecyclerAdapter.addFooterView(view); 
        } 
    } 
  
    // 移除头部  
    public void removeHeaderView(View view) { 
        if (mWrapRecyclerAdapter != null) { 
            mWrapRecyclerAdapter.removeHeaderView(view); 
        } 
    } 
  
    // 移除底部  
    public void removeFooterView(View view) { 
        if (mWrapRecyclerAdapter != null) { 
            mWrapRecyclerAdapter.removeFooterView(view); 
        } 
    } 
  
    private AdapterDataObserver mDataObserver = new AdapterDataObserver() { 
        @Override 
        public void onChanged() { 
            if (mAdapter == null) return; 
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果 
             if (mWrapRecyclerAdapter != mAdapter) 
                mWrapRecyclerAdapter.notifyDataSetChanged(); 
 
            dataChanged(); 
        } 
 
        @Override 
        public void onItemRangeRemoved(int positionStart, int itemCount) { 
            if (mAdapter == null) return; 
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果 
            if (mWrapRecyclerAdapter != mAdapter) 
                mWrapRecyclerAdapter.notifyItemRemoved(positionStart); 
            dataChanged(); 
        } 
 
        @Override 
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { 
            if (mAdapter == null) return; 
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemMoved没效果 
            if (mWrapRecyclerAdapter != mAdapter) 
                mWrapRecyclerAdapter.notifyItemMoved(fromPosition, toPosition); 
            dataChanged(); 
        } 
 
        @Override 
        public void onItemRangeChanged(int positionStart, int itemCount) { 
            if (mAdapter == null) return; 
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果 
            if (mWrapRecyclerAdapter != mAdapter) 
                mWrapRecyclerAdapter.notifyItemChanged(positionStart); 
            dataChanged(); 
        } 
 
        @Override 
        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { 
            if (mAdapter == null) return; 
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果 
            if (mWrapRecyclerAdapter != mAdapter) 
                mWrapRecyclerAdapter.notifyItemChanged(positionStart, payload); 
            dataChanged(); 
        } 
 
        @Override 
        public void onItemRangeInserted(int positionStart, int itemCount) { 
            if (mAdapter == null) return; 
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemInserted没效果 
            if (mWrapRecyclerAdapter != mAdapter) 
                mWrapRecyclerAdapter.notifyItemInserted(positionStart); 
            dataChanged(); 
        } 
    }; 
 
    /** 
     * 添加一个空列表数据页面 
     */ 155     public void addEmptyView(View emptyView) { 
        this.mEmptyView = emptyView; 
    } 
 
    /** 
     * 添加一个正在加载数据的页面 
     */ 
    public void addLoadingView(View loadingView) { 
        this.mLoadingView = loadingView; 
        mLoadingView.setVisibility(View.VISIBLE); 
    } 
 
    /** 
     * Adapter数据改变的方法 
     */ 
    private void dataChanged() { 
        if (mAdapter.getItemCount() == 0) { 
            // 没有数据 
            if (mEmptyView != null) { 
                mEmptyView.setVisibility(VISIBLE); 
            } 
        } else { 
            // 没有数据 
            if (mEmptyView != null) { 
                mEmptyView.setVisibility(GONE); 
            } 
        } 
    } 
 
    /*************** 
     * 给条目设置点击和长按事件 
     *********************/ 
    public com.zzw.framelibray.recyclerview.adapter.OnItemClickListener mItemClickListener; 
    public com.zzw.framelibray.recyclerview.adapter.OnLongClickListener mLongClickListener; 
 
    public void setOnItemClickListener(com.zzw.framelibray.recyclerview.adapter.OnItemClickListener itemClickListener) { 
        this.mItemClickListener = itemClickListener; 
 
        if (mWrapRecyclerAdapter != null) { 
            mWrapRecyclerAdapter.setOnItemClickListener(mItemClickListener); 
        } 
    } 
 
    public void setOnLongClickListener(com.zzw.framelibray.recyclerview.adapter.OnLongClickListener longClickListener) { 
        this.mLongClickListener = longClickListener; 
 
        if (mWrapRecyclerAdapter != null) { 
            mWrapRecyclerAdapter.setOnLongClickListener(mLongClickListener); 
        } 
    } 
}

3.使用:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical" android:layout_width="match_parent"  
    android:layout_height="match_parent"> 
  
    <com.zzw.framelibray.recyclerview.view.WrapRecyclerView 
        android:id="@+id/wrap_recycler_view"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent" 
  
         /> 
 
</LinearLayout>

Activity
public class HeaderFooterActivity extends AppCompatActivity implements OnItemClickListener { 
  
    private WrapRecyclerView mRecyclerView; 
    private List<People> mData; 
  
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_recycler_view); 
        mRecyclerView = (WrapRecyclerView) findViewById(R.id.wrap_recycler_view); 
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 
 
        mData =new ArrayList<>(); 
        mData.add(new People()); 
        mData.add(new People()); 
        mData.add(new People()); 
 
        PeopleListAdapter listAdapter = new PeopleListAdapter(this, mData); 
 
        // 添加头部和底部 需要 包裹Adapter,才能添加头部和底部 
        WrapRecyclerAdapter wrapRecyclerAdapter = new WrapRecyclerAdapter(listAdapter); 
        mRecyclerView.setAdapter(wrapRecyclerAdapter); 
 
        wrapRecyclerAdapter.setOnItemClickListener(this); 
 
        // 添加头部和底部 
        wrapRecyclerAdapter.addHeaderView(LayoutInflater.from(this).inflate(R.layout.layout_header,mRecyclerView,false)); 
        wrapRecyclerAdapter.addFooterView(LayoutInflater.from(this).inflate(R.layout.layout_header,mRecyclerView,false)); 
    } 
 
    @Override 
    public void onItemClick(View view, int position) { 
        Toast.makeText(this, "" + mData.get(position).name, Toast.LENGTH_SHORT).show(); 
    } 
 
    class PeopleListAdapter extends CommonRecyclerAdapter<People> { 
 
        public PeopleListAdapter(Context context, List<People> datas) { 
            super(context, datas, R.layout.channel_list_item); 
        } 
 
        @Override 
        public void convert(ViewHolder holder, People item, int position) { 
            holder.setText(R.id.action_btn, item.name+position); 
        } 
    } 
 
    class People{ 
        String name="王伟:"; 
    } 
}

 

原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/aiops/3091.html

(0)
上一篇 2021年7月16日 14:03
下一篇 2021年7月16日 14:03

相关推荐

发表回复

登录后才能评论