最近在开发过程中,遇到这样一个需求,就是对数组分组显示,在网上找了很多方案,但都讲得不全面,在此记录一下自己实践成功的方案。如下图:
S80831-173502.jpg
具体步骤
第一步、使用RecycleView实现,并设置layoutManager为GridLayoutManager。
int column = Utils.calculateCashBackStoreSpanCount(getContext());
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), column);
recycleView.setLayoutManager(layoutManager);
第二步、使adapter支持多类型,例如:
需要加入开源库
versions.base_adapter = "3.0.3"
compile "com.zhy:base-rvadapter:$versions.base_adapter"
public class StoreGridAdapter extends MultiItemTypeAdapter<Object> {
public static int ITEM_TYPE_ADS = 2;
public static int ITEM_TYPE_LABEL = 1;
public static int ITEM_TYPE_STORE = 0;
public StoreGridAdapter(Context context, List<Object> list) {
super(context, list);
addItemViewDelegate(ITEM_TYPE_LABEL, new LabelItemViewDelegate());
addItemViewDelegate(ITEM_TYPE_STORE, new StoreItemViewDelegate());
addItemViewDelegate(ITEM_TYPE_ADS, new AdsItemViewDelegate());
}
class LabelItemViewDelegate implements ItemViewDelegate<Object> {
@Override
public int getItemViewLayoutId() {
return R.layout.item_store_first_letter_lay;
}
@Override
public boolean isForViewType(Object item, int position) {
return (item instanceof String);
}
@Override
public void convert(ViewHolder holder, Object item, int position) {
String label = (String) item;
TextView tv = holder.getView(R.id.text);
tv.setText(Formatter.toUpperOfFirst(label));
}
}
class StoreItemViewDelegate implements ItemViewDelegate<Object> {
@Override
public int getItemViewLayoutId() {
return R.layout.item_grid_store_lay;
}
@Override
public boolean isForViewType(Object item, int position) {
return (item instanceof StoreItem);
}
@Override
public void convert(ViewHolder holder, Object o, int position) {
final StoreItem storeItem = (StoreItem) o;
ImageView logoImg = holder.getView(R.id.itemStoreLogo);
TextView cashBackTxt = holder.getView(R.id.itemCashback);
CommonImageLoader.displayImage(mContext, storeItem.storeLogo, logoImg);
cashBackTxt.setText(storeItem.cashbackValue);
holder.getConvertView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onStoreClick(storeItem);
}
});
}
}
class AdsItemViewDelegate implements ItemViewDelegate<Object> {
@Override
public int getItemViewLayoutId() {
return R.layout.layout_ads;
}
@Override
public boolean isForViewType(Object item, int position) {
return (item instanceof AdGroup);
}
@Override
public void convert(ViewHolder holder, Object o, int position) {
AdGroup group = (AdGroup) o;
AdsGroupView adsView = holder.getView(R.id.ads);
adsView.showAds(group.adGroup);
}
}
//计算每一行显示的列数
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if(manager instanceof GridLayoutManager) {
final GridLayoutManager gridManager = ((GridLayoutManager) manager);
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return (getItemViewType(position) == ITEM_TYPE_LABEL
|| getItemViewType(position) == ITEM_TYPE_ADS)
? gridManager.getSpanCount() : 1;
}
});
}
}
private void onStoreClick(StoreItem storeItem) {
}
}
第三步、计算间距。大概说一下算法:首先识别item是否是label,然后设置label间距;其次计算item所在位置是不是新行开始。代码如下:
class MyItemDecoration extends RecyclerView.ItemDecoration {
private int space;
private int spanCount;
MyItemDecoration (int cols, int space){
this.spanCount = cols;
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
int position = parent.getChildAdapterPosition(view); // item position
spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
if(position == 0) {
outRect.top = space;
}
if(isAds(parent, position)) {
outRect.top = 0;
outRect.left = 0;
outRect.right = 0;
}else if(isLabel(parent, position)) {
//label
outRect.left = space*2;
outRect.right = space;
}else{
if(isNewLine(parent, position)) {
outRect.left = space;
outRect.right = space;
}else{
outRect.right = space;
}
}
outRect.bottom = space;
}
private boolean isLabel(RecyclerView parent, int position){
int viewType = parent.getAdapter().getItemViewType(position);
return (viewType == AllStoreGridAdapter.ITEM_TYPE_LABEL);
}
private boolean isNewLine(RecyclerView parent, int position){
boolean newLine = false;
if(isLabel(parent, position-1)){
return true;
}
int startIndex = findAreaStartIndex(parent, position);
if(startIndex > -1) {
return ((position-1 - startIndex) % spanCount == 0);
}
return newLine;
}
private int findAreaStartIndex(RecyclerView parent, int position){
for(int i=position; i<= position; i--){
if(isLabel(parent, i)){
return i;
}
}
return -1;
}
private boolean isAds(RecyclerView parent, int position){
int viewType = parent.getAdapter().getItemViewType(position);
return (viewType == AllStoreGridAdapter.ITEM_TYPE_ADS);
}
}
总结
RecycleView控件可以绘制出各种各样的布局效果,秘诀就是合理使用layoutManager,动态item的带下和间距。
网友评论