RecyclerView+GridView分组效果
2016-12-28 18:06
489 查看
首先,不上图就是耍流氓!
项目中要做图中类似的效果。
方案一:
RecyclerView嵌套RecyclerView
缺点:页面卡顿
结果:放弃该方案
方案二:
重写适配器
缺点:需要做数据处理(可接受)
优点:顺滑无比,不用嵌套,不用修改recyclerview
结果:使用该方案
使用过程中,愈发感觉RecyclerView的强大,服,是真服!
借鉴了github的开源项目,在此对作者表示感谢。
地址:SectionedRecyclerView
开始使用
RecyclerView照常写就好,这里需要注意的Adapter。先说一下整个设计思路:在adapter 设置分组数getSectionCount , 设置每一组的个数getItemCountForSection,根据这个关键数据,把header和footer视为一个单项,计算出总共的单项数目,然后根据不同的类型,header,footer,item,让GridLayoutManager的getSpanSize不同,即可达到效果。
连个关键
一:在于记录每一个单项(包括头部和底部单项的 )详细属性,
1,是头部,正常,还是底部
2,在哪一个分组,又在分组的第一个位置
二:当是header或者footer是,将GridLayoutManger的spanSize设为全屏
来看下SectionedSpanSizeLookup的实现,这个就是用来处理每一项显示的宽度大小的,神奇的东西
下面来看一下Adapter的实现,
这个没什么讲的,就是普通的用法,注意两个方法,getSectionCount()和getItemCountForSection(),还有一个方法getSectionHeaderTitle()用于设置显示的分组名,显然父类中已经进行了完美的封装,下面我们来看父类
而这个父类这是封装了header和footer的显示,至于header和footer是如何判断?以及如何 根据分组数和每个分组的个数 绘制出我们要的效果?这些问题还得再找父类,找的爷爷辈,别急,继续看,
项目中要做图中类似的效果。
方案一:
RecyclerView嵌套RecyclerView
缺点:页面卡顿
结果:放弃该方案
方案二:
重写适配器
缺点:需要做数据处理(可接受)
优点:顺滑无比,不用嵌套,不用修改recyclerview
结果:使用该方案
使用过程中,愈发感觉RecyclerView的强大,服,是真服!
借鉴了github的开源项目,在此对作者表示感谢。
地址:SectionedRecyclerView
开始使用
RecyclerView照常写就好,这里需要注意的Adapter。先说一下整个设计思路:在adapter 设置分组数getSectionCount , 设置每一组的个数getItemCountForSection,根据这个关键数据,把header和footer视为一个单项,计算出总共的单项数目,然后根据不同的类型,header,footer,item,让GridLayoutManager的getSpanSize不同,即可达到效果。
连个关键
一:在于记录每一个单项(包括头部和底部单项的 )详细属性,
1,是头部,正常,还是底部
2,在哪一个分组,又在分组的第一个位置
二:当是header或者footer是,将GridLayoutManger的spanSize设为全屏
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 5); SectionedSpanSizeLookup lookup = new SectionedSpanSizeLookup(mAdapter, layoutManager); layoutManager.setSpanSizeLookup(lookup);
来看下SectionedSpanSizeLookup的实现,这个就是用来处理每一项显示的宽度大小的,神奇的东西
public class SectionedSpanSizeLookup extends GridLayoutManager.SpanSizeLookup { protected SectionedRecyclerViewAdapter<?, ?, ?> adapter = null; protected GridLayoutManager layoutManager = null; public SectionedSpanSizeLookup(SectionedRecyclerViewAdapter<?, ?, ?> adapter, GridLayoutManager layoutManager) { this.adapter = adapter; this.layoutManager = layoutManager; } @Override public int getSpanSize(int position) { if(adapter.isSectionHeaderPosition(position) || adapter.isSectionFooterPosition(position)){ return layoutManager.getSpanCount(); }else{ return 1; } } }
下面来看一下Adapter的实现,
public class RoomPreAdapter2 extends SimpleSectionedAdapter2<RoomPreAdapter2.RoomHodler> { private Context context; @Override protected String getSectionHeaderTitle(int section) { return section + "#"; } /** * 获取分组数 * @return */ @Override protected int getSectionCount() { return 10; } /** * 获取指定组的个数 * @param section * @return */ @Override protected int getItemCountForSection(int section) { return section + 6; } @Override protected RoomHodler onCreateItemViewHolder(ViewGroup parent, int viewType) { context = parent.getContext(); View itemView = LayoutInflater.from(context).inflate(R.layout.item_room, parent, false); return new RoomHodler(itemView); } @Override protected void onBindItemViewHolder(RoomHodler holder, int section, final int position) { holder.rb_room.setText(section + "-" + position); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(context, "点了" + position, Toast.LENGTH_SHORT).show(); } }); holder.rb_room.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { Toast.makeText(context, "选了" + position, Toast.LENGTH_SHORT).show(); } }); } class RoomHodler extends RecyclerView.ViewHolder { RadioButton rb_room; public RoomHodler(View itemView) { super(itemView); rb_room = (RadioButton) itemView.findViewById(R.id.rb_room); } } }
这个没什么讲的,就是普通的用法,注意两个方法,getSectionCount()和getItemCountForSection(),还有一个方法getSectionHeaderTitle()用于设置显示的分组名,显然父类中已经进行了完美的封装,下面我们来看父类
public abstract class SimpleSectionedAdapter2<VH < 4000 span class="hljs-keyword">extends RecyclerView.ViewHolder> extends SectionedRecyclerViewAdapter<HeaderViewHolder, VH, RecyclerView.ViewHolder> { /** * 是否显示每一个分组的底部 * @param section * @return */ @Override protected boolean hasFooterInSection(int section) { return true; } /* 创建头部header的ViewHolder */ @Override protected HeaderViewHolder onCreateSectionHeaderViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(getLayoutResource(), parent, false); HeaderViewHolder holder = new HeaderViewHolder(view, getTitleTextID()); return holder; } /* 创建底部footer的ViewHolder */ @Override protected RecyclerView.ViewHolder onCreateSectionFooterViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(getFooterLayoutResource(), parent, false); FooterViewHolder holder = new FooterViewHolder(view); return holder; } private int getFooterLayoutResource() { return R.layout.item_room_footer; } @Override protected void onBindSectionHeaderViewHolder(HeaderViewHolder holder, int section) { String title = getSectionHeaderTitle(section); holder.render(title); } @Override protected void onBindSectionFooterViewHolder(RecyclerView.ViewHolder holder, int section) { } /** * Provides a layout identifier for the header. Override it to change the appearance of the * header view. */ protected @LayoutRes int getLayoutResource() { return R.layout.item_room_header; } /** * Provides the identifier of the TextView to render the section header title. Override it if * you provide a custom layout for a header. */ protected @IdRes int getTitleTextID() { return R.id.tv_group_name; } /** * Returns the title for a given section */ protected abstract String getSectionHeaderTitle(int section); /** * 底部Footer的ViewHolder */ class FooterViewHolder extends RecyclerView.ViewHolder{ public FooterViewHolder(View itemView) { super(itemView); } } }
而这个父类这是封装了header和footer的显示,至于header和footer是如何判断?以及如何 根据分组数和每个分组的个数 绘制出我们要的效果?这些问题还得再找父类,找的爷爷辈,别急,继续看,
public abstract class SectionedRecyclerViewAdapter<H extends RecyclerView.ViewHolder, VH extends RecyclerView.ViewHolder, F extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<RecyclerView.ViewHolder> { protected static final int TYPE_SECTION_HEADER = -1; protected static final int TYPE_SECTION_FOOTER = -2; protected static final int TYPE_ITEM = -3; //用四个数组,对应保存每一个单项(包括header和footer)的四个属性 //1.哪个分组;2.在该组的位置;3.是否是头部;4.是否是底部; private int[] sectionForPosition = null; private int[] positionWithinSection = null; private boolean[] isHeader = null; private boolean[] isFooter = null; private int count = 0; public SectionedRecyclerViewAdapter() { super(); registerAdapterDataObserver(new SectionDataObserver()); } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); setupIndices(); } /** * Returns the sum of number of items for each section plus headers and footers if they * are provided. */ @Override public int getItemCount() { return count; } private void setupIndices(){ count = countItems(); allocateAuxiliaryArrays(count); precomputeIndices(); } private int countItems() { int count = 0; int sections = getSectionCount(); //计算总个数 for(int i = 0; i < sections; i++){ count += 1 + getItemCountForSection(i) + (hasFooterInSection(i) ? 1 : 0); } return count; } //为每一个单项,设置四大属性 private void precomputeIndices(){ int sections = getSectionCount(); int index = 0; for(int i = 0; i < sections; i++){ setPrecomputedItem(index, true, false, i, 0); index++; for(int j = 0; j < getItemCountForSection(i); j++){ setPrecomputedItem(index, false, false, i, j); index++; } if(hasFooterInSection(i)){ setPrecomputedItem(index, false, true, i, 0); index++; } } } private void allocateAuxiliaryArrays(int count) { sectionForPosition = new int[count]; positionWithinSection = new int[count]; isHeader = new boolean[count]; isFooter = new boolean[count]; } private void setPrecomputedItem(int index, boolean isHeader, boolean isFooter, int section, int position) { this.isHeader[index] = isHeader; this.isFooter[index] = isFooter; sectionForPosition[index] = section; positionWithinSection[index] = position; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerView.ViewHolder viewHolder; if(isSectionHeaderViewType(viewType)){ viewHolder = onCreateSectionHeaderViewHolder(parent, viewType); }else if(isSectionFooterViewType(viewType)){ viewHolder = onCreateSectionFooterViewHolder(parent, viewType); }else{ viewHolder = onCreateItemViewHolder(parent, viewType); } return viewHolder; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { int section = sectionForPosition[position]; int index = positionWithinSection[position]; if(isSectionHeaderPosition(position)){ onBindSectionHeaderViewHolder((H) holder, section); }else if(isSectionFooterPosition(position)){ onBindSectionFooterViewHolder((F) holder, section); }else{ onBindItemViewHolder((VH) holder, section, index); } } @Override public int getItemViewType(int position) { if(sectionForPosition == null){ setupIndices(); } int section = sectionForPosition[position]; int index = positionWithinSection[position]; if(isSectionHeaderPosition(position)){ return getSectionHeaderViewType(section); }else if(isSectionFooterPosition(position)){ return getSectionFooterViewType(section); }else{ return getSectionItemViewType(section, index); } } protected int getSectionHeaderViewType(int section){ return TYPE_SECTION_HEADER; } protected int getSectionFooterViewType(int section){ return TYPE_SECTION_FOOTER; } protected int getSectionItemViewType(int section, int position){ return TYPE_ITEM; } /** * Returns true if the argument position corresponds to a header */ public boolean isSectionHeaderPosition(int position){ if(isHeader == null){ setupIndices(); } return isHeader[position]; } /** * Returns true if the argument position b423 corresponds to a footer */ public boolean isSectionFooterPosition(int position){ if(isFooter == null){ setupIndices(); } return isFooter[position]; } protected boolean isSectionHeaderViewType(int viewType){ return viewType == TYPE_SECTION_HEADER; } protected boolean isSectionFooterViewType(int viewType){ return viewType == TYPE_SECTION_FOOTER; } /** * Returns the number of sections in the RecyclerView */ protected abstract int getSectionCount(); /** * Returns the number of items for a given section */ protected abstract int getItemCountForSection(int section); /** * Returns true if a given section should have a footer */ protected abstract boolean hasFooterInSection(int section); /** * Creates a ViewHolder of class H for a Header */ protected abstract H onCreateSectionHeaderViewHolder(ViewGroup parent, int viewType); /** * Creates a ViewHolder of class F for a Footer */ protected abstract F onCreateSectionFooterViewHolder(ViewGroup parent, int viewType); /** * Creates a ViewHolder of class VH for an Item */ protected abstract VH onCreateItemViewHolder(ViewGroup parent, int viewType); /** * Binds data to the header view of a given section */ protected abstract void onBindSectionHeaderViewHolder(H holder, int section); /** * Binds data to the footer view of a given section */ protected abstract void onBindSectionFooterViewHolder(F holder, int section); /** * Binds data to the item view for a given position within a section */ protected abstract void onBindItemViewHolder(VH holder, int section, int position); class SectionDataObserver extends RecyclerView.AdapterDataObserver{ @Override public void onChanged() { setupIndices(); } @Override public void onItemRangeChanged(int positionStart, int itemCount) { setupIndices(); } @Override public void onItemRangeInserted(int positionStart, int itemCount) { setupIndices(); } @Override public void onItemRangeRemoved(int positionStart, int itemCount) { setupIndices(); } @Override public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { setupIndices(); } }
相关文章推荐
- 用RecyclerView轻松实现gridview中itemview拖拽效果
- Android RecyclerView (二)初学,实现GridView列表和瀑布流效果。
- RecyclerView的基本用法 (一个控件实现ListView, GridView等效果)+接口回调点击事件
- Android RecyclerView详解之实现 ListView GridView瀑布流效果
- Android Recyclerview实现水平分页GridView效果示例
- RecyclerView--实现 ListView,GridView,瀑布流 效果
- 使用RecyclerView实现ListView,GridView的效果(上下,左右滑动),拖拽与滑动删除
- 使用RecyclerView实现GridView和ListView混排的效果
- BaseRecyclerViewAdapterHelper开源项目之BaseSectionQuickAdapter 实现分组效果的源码学习
- RecyclerView表格展示GridView加HeadView效果
- Android 从零开始实现RecyclerView分组及粘性头部效果
- RecyclerView介绍(三)----实现GridView效果
- RecyclerView实现 gridview效果!
- 使用RecyclerView实现ListView,GridView效果
- 基于RecyclerView实现横向GridView效果
- android RecyclerView一步步打造分组效果、类似QQ分组、折叠菜单、分组效果(二)
- Recyclerview最最简单实现水平分页GridView效果
- (4.1.45.2)RecyclerView实现带header的GridView效果:添加viewType方式
- RecyclerView表格展示GridView加HeadView效果
- RecyclerView实现横向的GridView效果