一. 效果图
1. 动态添加和删除头部
2. 动态添加和删除底部
二. 使用
通过调用WrapRecyclerView封装好的添加和删除头部与底部的方法
package com.xinhua.wraprecyclerviewdemo;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.xinhua.wraprecyclerviewdemo.recyclerview.MyRecyclerAdapter;
import com.xinhua.wraprecyclerviewdemo.recyclerview.WrapRecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private WrapRecyclerView mRecyclerView;
private Button mBtnAddHeaderTop, mBtnAddHeaderCenter, mBtnAddHeaderBottom;
private Button mBtnAddFooterTop, mBtnAddFooterCenter, mBtnAddFooterBottom;
private Button mBtnDelHeaderIndex, mBtnDelHeaderView, mBtnDelHeaderBottom;
private Button mBtnDelFooterIndex, mBtnDelFooterView, mBtnDelFooterBottom;
private TextView mHeadertexttView1, mHeadertexttView2, mHeadertexttView3, mHeadertexttView4;
private TextView mFootertexttView1, mFootertexttView2, mFootertexttView3, mFootertexttView4;
private List mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initView() {
mRecyclerView = findViewById(R.id.recycler_view);
mBtnAddHeaderTop = findViewById(R.id.btn_addHeader_top);
mBtnAddHeaderCenter = findViewById(R.id.btn_addHeader_center);
mBtnAddHeaderBottom = findViewById(R.id.btn_addHeader_bottom);
mBtnAddFooterTop = findViewById(R.id.btn_addFooter_top);
mBtnAddFooterCenter = findViewById(R.id.btn_addFooter_center);
mBtnAddFooterBottom = findViewById(R.id.btn_addFooter_bottom);
mBtnDelHeaderIndex = findViewById(R.id.btn_deleteHeader_index);
mBtnDelHeaderView = findViewById(R.id.btn_deleteHeader_view);
mBtnDelHeaderBottom = findViewById(R.id.btn_deleteHeader_bottom);
mBtnDelFooterIndex = findViewById(R.id.btn_deleteFooter_index);
mBtnDelFooterView = findViewById(R.id.btn_deleteFooter_view);
mBtnDelFooterBottom = findViewById(R.id.btn_deleteFooter_bottom);
mBtnAddHeaderTop.setOnClickListener(this);
mBtnAddHeaderCenter.setOnClickListener(this);
mBtnAddHeaderBottom.setOnClickListener(this);
mBtnAddFooterTop.setOnClickListener(this);
mBtnAddFooterCenter.setOnClickListener(this);
mBtnAddFooterBottom.setOnClickListener(this);
mBtnDelHeaderIndex.setOnClickListener(this);
mBtnDelHeaderView.setOnClickListener(this);
mBtnDelHeaderBottom.setOnClickListener(this);
mBtnDelFooterIndex.setOnClickListener(this);
mBtnDelFooterView.setOnClickListener(this);
mBtnDelFooterBottom.setOnClickListener(this);
//新增头部
mHeadertexttView1 = new TextView(this);
mHeadertexttView1.setText("新增头部文字1");
mHeadertexttView2 = new TextView(this);
mHeadertexttView2.setText("新增头部文字2");
mHeadertexttView3 = new TextView(this);
mHeadertexttView3.setText("新增头部文字3");
mHeadertexttView4 = new TextView(this);
mHeadertexttView4.setText("新增头部文字4");
//新增底部
mFootertexttView1 = new TextView(this);
mFootertexttView1.setText("新增底部文字1");
mFootertexttView2 = new TextView(this);
mFootertexttView2.setText("新增底部文字2");
mFootertexttView3 = new TextView(this);
mFootertexttView3.setText("新增底部文字3");
mFootertexttView4 = new TextView(this);
mFootertexttView4.setText("新增底部文字4");
//添加
mRecyclerView.addHeaderView(mHeadertexttView1);
mRecyclerView.addHeaderView(mHeadertexttView2);
mRecyclerView.addHeaderView(mHeadertexttView3);
mRecyclerView.addHeaderView(mHeadertexttView4);
mRecyclerView.addFooterView(mFootertexttView1);
mRecyclerView.addFooterView(mFootertexttView2);
mRecyclerView.addFooterView(mFootertexttView3);
mRecyclerView.addFooterView(mFootertexttView4);
}
private void initData() {
mList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
mList.add("测试数据 -> " + i);
}
mRecyclerView.setAdapter(new MyRecyclerAdapter(this, mList));
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_addHeader_top:
//添加指定index位置的头部,添加布局文件
mRecyclerView.addHeaderView(R.layout.layout_header_view1, 0);
break;
case R.id.btn_addHeader_center:
//添加指定index位置的头部,添加自定义View
View headerLayoutView = LayoutInflater.from(this).inflate(R.layout.layout_header_view2, null, false);
mRecyclerView.addHeaderView(headerLayoutView, 2);
break;
case R.id.btn_addHeader_bottom:
//添加末端头部,添加布局文件
mRecyclerView.addHeaderView(R.layout.layout_header_view3);
break;
case R.id.btn_addFooter_top:
View footerLayoutView = LayoutInflater.from(this).inflate(R.layout.layout_footer_view1, null, false);
mRecyclerView.addFooterView(footerLayoutView, 0);
break;
case R.id.btn_addFooter_center:
mRecyclerView.addFooterView(R.layout.layout_footer_view2, 2);
break;
case R.id.btn_addFooter_bottom:
mRecyclerView.addFooterView(R.layout.layout_footer_view3);
break;
case R.id.btn_deleteHeader_index:
//通过index删除指定位置的头部
mRecyclerView.removeHeaderViewWithIndex(1);
break;
case R.id.btn_deleteHeader_view:
//删除指定view的头部
mRecyclerView.removeHeaderView(mHeadertexttView3);
break;
case R.id.btn_deleteHeader_bottom:
//删除最后一个头部
mRecyclerView.removeHeaderViewWithIndex(mRecyclerView.getHeaderItemCount() - 1);
break;
case R.id.btn_deleteFooter_index:
mRecyclerView.removeFooterViewWithIndex(1);
break;
case R.id.btn_deleteFooter_view:
mRecyclerView.removeFooterView(mFootertexttView3);
break;
case R.id.btn_deleteFooter_bottom:
mRecyclerView.removeFooterViewWithIndex(mRecyclerView.getFooterItemCount() - 1);
break;
}
}
}
三.实现
1. 构建RecyclerViewAdapter
根据不同类型返回不同的ViewType来创建不同的ViewHolder,实现区分头部、正常item、底部
public class WrapRecyclerAdapter extends RecyclerView.Adapter {
private RecyclerView.Adapter mAdapter;
private SparseArray mHeaderViews;
private SparseArray mFooterViews;
private List mHeaderKey;
private List mFooterKey;
public WrapRecyclerAdapter(Context context, RecyclerView.Adapter adapter) {
mAdapter = adapter;
mHeaderViews = new SparseArray<>();
mFooterViews = new SparseArray<>();
mHeaderKey = new ArrayList<>();
mFooterKey = new ArrayList<>();
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (mHeaderViews.get(viewType) != null) {
return new ViewHolder(mHeaderViews.get(viewType));
} else if (mFooterViews.get(viewType) != null) {
return new ViewHolder(mFooterViews.get(viewType));
}
return mAdapter.createViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (isHeaderView(position) || isFooterView(position)) {
return;
}
mAdapter.onBindViewHolder(holder, position - getHeaderItemCount());
}
@Override
public int getItemViewType(int position) {
if (isHeaderView(position)) {
return mHeaderKey.get(position);
} else if (isFooterView(position)) {
return mFooterKey.get(position - getHeaderItemCount() - getContentItemCount());
}
return mAdapter.getItemViewType(position - getHeaderItemCount());
}
protected void addHeaderView(View view) {
mHeaderKey.add(view.hashCode());
mHeaderViews.put(view.hashCode(), view);
}
protected void addHeaderView(View view, int index) {
mHeaderKey.add(index, view.hashCode());
mHeaderViews.put(view.hashCode(), view);
}
protected void addHeaderViewAndNotify(View view) {
mHeaderKey.add(view.hashCode());
mHeaderViews.put(view.hashCode(), view);
notifyItemInserted(getHeaderItemCount() - 1);
}
protected void addHeaderViewAndNotify(View view, int index) {
addHeaderView(view, index);
notifyItemInserted(index);
}
....
2. 构建WrapRecyclerView
构建WrapRecyclerView来实现对头部和底部的动态添加与删除
public class WrapRecyclerView extends RecyclerView {
private List mHeaderViews;
private ArrayMap mHeaderViewResMap;
private List mFooterViews;
private ArrayMap mFooterViewResMap;
private WrapRecyclerAdapter mWrapRecycleAdapter;
private Context mContext;
public WrapRecyclerView(@NonNull Context context) {
this(context, null);
}
public WrapRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public WrapRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
mHeaderViews = new ArrayList<>();
mFooterViews = new ArrayList<>();
mHeaderViewResMap = new ArrayMap<>();
mFooterViewResMap = new ArrayMap<>();
mContext = context;
}
@Override
public void setAdapter(@Nullable Adapter adapter) {
if (mWrapRecycleAdapter != null) {
mWrapRecycleAdapter.getOriginAdapter().unregisterAdapterDataObserver(mAdapterDataObserver);
}
if (adapter == null) {
mWrapRecycleAdapter = null;
} else {
adapter.registerAdapterDataObserver(mAdapterDataObserver);
mWrapRecycleAdapter = new WrapRecyclerAdapter(getContext(), adapter);
for (int i = 0; i < mHeaderViews.size(); i++) {
mWrapRecycleAdapter.addHeaderView(mHeaderViews.get(i));
}
if (mFooterViews.size() > 0) {
for (View footerView : mFooterViews) {
mWrapRecycleAdapter.addFooterView(footerView);
}
}
}
super.setAdapter(mWrapRecycleAdapter);
}
public void addHeaderView(View view) {
if (view == null) {
throw new IllegalArgumentException("view is null on addHeaderView(View view)");
}
if (!mHeaderViews.contains(view)) {
mHeaderViews.add(view);
if (mWrapRecycleAdapter != null) {
mWrapRecycleAdapter.addHeaderViewAndNotify(view);
}
}
}
public void addHeaderView(View view, int index) {
if (index < 0 || index > mHeaderViews.size()) {
throw new IllegalArgumentException("index out of bounds on addHeaderView(View view, int index)");
}
if (!mHeaderViews.contains(view)) {
mHeaderViews.add(index, view);
if (mWrapRecycleAdapter != null) {
mWrapRecycleAdapter.addHeaderViewAndNotify(view, index);
if (index == 0) {
scrollToPosition(index);
}
}
}
}
/**
* recyclerView添加头部view
*
* @param layoutId 布局文件
*/
public void addHeaderView(@LayoutRes int layoutId) {
if (layoutId == 0) {
throw new IllegalArgumentException("layoutId is invalid on addHeaderView(int layoutId)");
}
if (!mHeaderViewResMap.containsKey(layoutId)) {
View view = LayoutInflater.from(mContext).inflate(layoutId, null, false);
if (view == null) {
throw new IllegalArgumentException("view is null on addHeaderView(View view)");
}
mHeaderViewResMap.put(layoutId, view);
addHeaderView(view);
}
}
public void addHeaderView(@LayoutRes int layoutId, int index) {
if (layoutId == 0) {
throw new IllegalArgumentException("layoutId is invalid on addHeaderView(int layoutId)");
}
if (!mHeaderViewResMap.containsKey(layoutId)) {
View view = LayoutInflater.from(mContext).inflate(layoutId, null, false);
if (view == null) {
throw new IllegalArgumentException("view is null on addHeaderView(View view)");
}
mHeaderViewResMap.put(layoutId, view);
addHeaderView(view, index);
}
}
....
}
- 项目地址
https://github.com/summer-0/WrapRecyclerView