一个精简的实现RecyclerView可添加header和footer的Demo
2016-08-27 15:38
603 查看
一个精简的实现RecyclerView可添加header和footer的Demo
实现思路很简单,就是把用户设置给RecyclerView的Adapter进行再封装,封装的内部类ExtraItemAdapter负责管理用户添加的header和footer。在onBind等方法中计算出偏移后的position再调用用户设置的原生adapter。
public class MyRecyclerView extends RecyclerView { protected ArrayList<View> mHeaderViews = new ArrayList<>(); protected ArrayList<View> mFooterViews = new ArrayList<>(); public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void setAdapter(@NonNull Adapter adapter) { super.setAdapter(new ExtraItemAdpater(adapter)); } public void addHeaderView(@NonNull View headerView) { addHeaderView(mHeaderViews.size(), headerView); } public void addHeaderView(int index, @NonNull View headerView) { if (index >= 0 && index <= mHeaderViews.size()) { mHeaderViews.add(index, headerView); if (getAdapter() != null) { getAdapter().notifyItemInserted(index); } } } public void removeHeaderView(@NonNull View headerView) { int index = mHeaderViews.indexOf(headerView); if (index != -1) { mHeaderViews.remove(index); if (getAdapter() != null) { getAdapter().notifyItemRemoved(index); } } } public void addFooterView(@NonNull View footerView) { addFooterView(mFooterViews.size(), footerView); } public void addFooterView(int index, @NonNull View footerView) { if (index >= 0 && index <= mFooterViews.size()) { mFooterViews.add(index, footerView); if (getAdapter() != null) { getAdapter().notifyItemInserted(mHeaderViews.size() + ((ExtraItemAdpater)getAdapter()).getNormaItemNum() + index); } } } public void removeFooterView(@NonNull View footerView) { int index = mFooterViews.indexOf(footerView); if (index != -1) { mFooterViews.remove(index); if (getAdapter() != null) { getAdapter().notifyItemRemoved(getAdapter().getItemCount() - mFooterViews.size() + index); } } } public int getHeaderViewsCount() { return mHeaderViews.size(); } public int getFooterViewsCount() { return mFooterViews.size(); } private class ExtraItemAdpater extends Adapter { private Adapter mAdapter; public ExtraItemAdpater(Adapter adapter) { this.mAdapter = adapter; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == Integer.MAX_VALUE) { return new ExtraViewHolder(new FrameLayout(parent.getContext())); } return mAdapter.onCreateViewHolder(parent, viewType); } @Override public void onBindViewHolder(ViewHolder holder, int position) { if (position >= mHeaderViews.size() && position < (getItemCount() - mFooterViews.size())) { mAdapter.onBindViewHolder(holder, position - mHeaderViews.size()); } else { bindExtraViewHolder(holder, position); } } @Override public int getItemCount() { return mHeaderViews.size() + mFooterViews.size() + getNormaItemNum(); } @Override public int getItemViewType(int position) { if (position >= mHeaderViews.size() && position < (getItemCount() - mFooterViews.size())) { return mAdapter.getItemViewType(position - mHeaderViews.size()); } return Integer.MAX_VALUE; } @Override public void registerAdapterDataObserver(AdapterDataObserver observer) { if(this.mAdapter != null) { this.mAdapter.registerAdapterDataObserver(observer); } super.registerAdapterDataObserver(observer); } @Override public void unregisterAdapterDataObserver(AdapterDataObserver observer) { if(this.mAdapter != null) { this.mAdapter.unregisterAdapterDataObserver(observer); } super.unregisterAdapterDataObserver(observer); } public int getNormaItemNum() { return mAdapter.getItemCount(); } } public class ExtraViewHolder extends ViewHolder { public ExtraViewHolder(View itemView) { super(itemView); } } private void bindExtraViewHolder(ViewHolder holder, int position) { ExtraViewHolder extraViewHolder = (ExtraViewHolder) holder; FrameLayout itemContainer = (FrameLayout) extraViewHolder.itemView; View extraView; if (position < mHeaderViews.size()) { extraView = mHeaderViews.get(position); } else { int index = position - mHeaderViews.size() - ((ExtraItemAdpater)getAdapter()).getNormaItemNum(); extraView = mFooterViews.get(index); } // 防止复用item造成view重复添加 itemContainer.removeAllViews(); ViewGroup parentView = (ViewGroup) extraView.getParent(); if (parentView != null) { parentView.removeAllViews(); } itemContainer.addView(extraView); // 让header和footer的LayoutParams兼容不同的布局,目前只考虑瀑布流布局 ViewGroup.LayoutParams lp = itemContainer.getLayoutParams(); if (lp == null) { lp = MyRecyclerView.this.generateDefaultLayoutParams(); itemContainer.setLayoutParams(lp); } if (lp instanceof StaggeredGridLayoutManager.LayoutParams) { ((StaggeredGridLayoutManager.LayoutParams) lp).setFullSpan(true); } } }
附加测试用的Adapter类
public class RVAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{ private final int NORMAL_ITEM_SIZE = 10; private final int TYPE_NORMAL = 0; private LayoutInflater mLayoutInflater; public RVAdapter(Context context){ mLayoutInflater = LayoutInflater.from(context); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_NORMAL : { return new NormalItemVH(mLayoutInflater.inflate(R.layout.item_layout, parent, false)); } default: return null; } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ((NormalItemVH)holder).render(position + ""); } @Override public int getItemCount() { return NORMAL_ITEM_SIZE; } @Override public int getItemViewType(int position) { return TYPE_NORMAL; } public static class NormalItemVH extends RecyclerView.ViewHolder { public TextView mTextView; public NormalItemVH(View itemView) { super(itemView); mTextView = (TextView) itemView.findViewById(R.id.textView); } public void render(String text) { mTextView.setText("normal-" + text); } } }
附加测试用的MainActivity(xml布局代码省略)
public class MainActivity extends AppCompatActivity { private MyRecyclerView mRecyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getSupportActionBar().hide(); setContentView(R.layout.activity_main); mRecyclerView = (MyRecyclerView) this.findViewById(R.id.recyclerView); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerView.setAdapter(new RVAdapter(this)); test(); } private void test() { for (int i = 0; i < 3; i ++) { final View header = LayoutInflater.from(this).inflate(R.layout.extra_item_layout, new FrameLayout(this), false); ((TextView)header.findViewById(R.id.textView)).setText("header-" + i); header.findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mRecyclerView.removeHeader(header); } }); mRecyclerView.addHeader(header); } for (int i = 0; i < 3; i ++) { final View footer = LayoutInflater.from(this).inflate(R.layout.extra_item_layout, new FrameLayout(this), false); ((TextView)footer.findViewById(R.id.textView)).setText("footer-" + i); footer.findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mRecyclerView.removeFooter(footer); } }); mRecyclerView.addFooter(footer); } } }
下面是运行效果图
点击remove按钮会删除header或者footer
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories