GridLayoutManager这么用,你可能还真没尝试过,kotlin开发android

private Boolean isDrawTitleBg = false;

private Context mContext;

// 总的SpanSize

private int totalSpanSize;

private int mCurrentSpanSize;

//… 省略一些方法

@Override

public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {

super.onDraw(c, parent, state);

// 绘制标题的逻辑:

// 如果该行的数据的需要显示的标题不同于上行的标题,就绘制标题

final int paddingLeft = parent.getPaddingLeft();

final int paddingRight = parent.getPaddingRight();

final int childCount = parent.getChildCount();

for (int i = 0; i < childCount; i++) {

View child = parent.getChildAt(i);

RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

int pos = params.getViewLayoutPosition();

IGridItem item = gridItems.get(pos);

if (item == null || !item.isShow())

continue;

if (i == 0) {

drawTitle(c, paddingLeft, paddingRight, child

, (RecyclerView.LayoutParams) child.getLayoutParams(), pos);

} else {

IGridItem lastItem = gridItems.get(pos - 1);

if (lastItem != null && !item.getTag().equals(lastItem.getTag())) {

drawTitle(c, paddingLeft, paddingRight, child,

(RecyclerView.LayoutParams) child.getLayoutParams(), pos);

}

}

}

}

/**

* 绘制标题

* @param canvas 画布

* @param pl     左边距

* @param pr     右边距

* @param child  子View

* @param params RecyclerView.LayoutParams

* @param pos    位置

*/

private void drawTitle(Canvas canvas, int pl, int pr, View child, RecyclerView.LayoutParams params, int pos) {

if (isDrawTitleBg) {

mTitlePaint.setColor(mTitleBgColor);

canvas.drawRect(pl, child.getTop() - params.topMargin - mTitleHeight, pl

, child.getTop() - params.topMargin, mTitlePaint);

}

IGridItem item = gridItems.get(pos);

String content = item.getTag();

if (TextUtils.isEmpty(content))

return;

mTitlePaint.setColor(mTitleColor);

mTitlePaint.setTextSize(mTitleFontSize);

mTitlePaint.setTypeface(Typeface.DEFAULT_BOLD);

mTitlePaint.getTextBounds(content, 0, content.length(), mRect);

float x = UIUtils.dip2px(20f);

float y = child.getTop() - params.topMargin - (mTitleHeight - mRect.height()) / 2;

canvas.drawText(content, x, y, mTitlePaint);

}

@Override

public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {

super.getItemOffsets(outRect, view, parent, state);

// 预留逻辑:

// 只要是标题下面的一行,无论这行几个,都要预留空间给标题显示

int position = parent.getChildAdapterPosition(view);

IGridItem item = gridItems.get(position);

if (item == null || !item.isShow())

return;

if (position == 0) {

outRect.set(0, mTitleHeight, 0, 0);

mCurrentSpanSize = item.getSpanSize();

} else {

if (!offsetPositions.isEmpty() && offsetPositions.contains(position)) {

outRect.set(0, mTitleHeight, 0, 0);

return;

}

if (!TextUtils.isEmpty(item.getTag()) && !item.getTag().equals(gridItems.get(position - 1).getTag())) {

mCurrentSpanSize = item.getSpanSize();

} else

mCurrentSpanSize += item.getSpanSize();

if (mCurrentSpanSize <= totalSpanSize) {

outRect.set(0, mTitleHeight, 0, 0);

offsetPositions.add(position);

}

}

}

}

总的逻辑就是:

  1. 如果所处的RecyclerView子视图的位置处在标题的下方,那么就需要预留空间GridLayoutManager这么用,你可能还真没尝试过,kotlin开发android
    ,设置在outRect中,需要注意的是,同一行的多个子视图都需要预留空间。

  2. 对不同于上一个数据标题的当前数据进行标题的绘制。

  3. 重复执行1、2。

2. 界面部分

public class SpecialGridActivity extends AppCompatActivity {

// GridItem实现了IGridItem接口

private List values;

private RecyclerView mRecyclerView;

private GridItemDecoration itemDecoration;

// 自己封装的RecyclerAdapter

private RecyclerAdapter mAdapter;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_special_grid);

initWidget();

}

private void initWidget() {

mRecyclerView = findViewById(R.id.rv_content);

// 创建GridLayoutManager,并设置SpanSizeLookup

GridLayoutManager gll = new GridLayoutManager(this, 3);

gll.setSpanSizeLookup(new SpecialSpanSizeLookup());

mRecyclerView.setLayoutManager(gll);

values = initData();

// 自己封装的RecyclerAdapter

mRecyclerView.setAdapter(mAdapter = new RecyclerAdapter(values,null) {

@Override

public ViewHolder onCreateViewHolder(View root, int viewType) {

switch (viewType) {

case R.layout.small_grid_recycle_item:

return new SmallHolder(root);

case R.layout.normal_grid_recycle_item:

return new NormalHolder(root);

case R.layout.special_grid_recycle_item:

return new SpecialHolder(root);

default:

return null;

}

}

@Override

public int getItemLayout(GridItem gridItem, int position) {

switch (gridItem.getType()) {

case GridItem.TYPE_SMALL:

return R.layout.small_grid_recycle_item;

case GridItem.TYPE_NORMAL:

return R.layout.normal_grid_recycle_item;

case GridItem.TYPE_SPECIAL:

return R.layout.special_grid_recycle_item;

}

return 0;

}

});

//…

// 分隔线生成

// 之前的GridItemDecoration代码中我将构建者模式部分省略了

itemDecoration = new GridItemDecoration.Builder(this,values, 3)

.setTitleTextColor(Color.parseColor("#4e5864"))

.setTitleFontSize(22)

.setTitleHeight(52)

.build();

mRecyclerView.addItemDecoration(itemDecoration);

}

// 数据初始化

private List initData() {

List values = new ArrayList<>();

values.add(new GridItem(“我很忙”, “”, R.drawable.head_1,“最近常听”,1,GridItem.TYPE_SMALL));

values.add(new GridItem(“治愈:有些歌比闺蜜更懂你”, “”, R.drawable.head_2,“最近常听”,1,GridItem.TYPE_SMALL));

values.add(new GridItem("「华语」90后的青春纪念手册", “”, R.drawable.head_3,“最近常听”,1,GridItem.TYPE_SMALL));

values.add(new GridItem(“流行创作女神你霉,泰勒斯威夫特的创作历程”, “”, R.drawable.special_2

,“更多为你推荐”,3,GridItem.TYPE_SPECIAL));

values.add(new GridItem(“行走的CD写给别人的歌”, “给「跟我走吧」几分,试试这些”, R.drawable.normal_1

,“更多为你推荐”,3,GridItem.TYPE_NORMAL));

values.add(new GridItem(“爱情里的酸甜苦辣,让人捉摸不透”, “听完「靠近一点点」,他们等你翻牌”, R.drawable.normal_2

,“更多为你推荐”,3,GridItem.TYPE_NORMAL));

values.add(new GridItem(“关于喜欢你这件事,我都写在了歌里”, “「好想你」听罢,听它们吧”, R.drawable.normal_3

,“更多为你推荐”,3,GridItem.TYPE_NORMAL));

values.add(new GridItem(“周杰伦暖心混剪,短短几分钟是多少人的青春”, “”, R.drawable.special_1

,“更多为你推荐”,3,GridItem.TYPE_SPECIAL));

values.add(new GridItem(“我好想和你一起听雨滴”, “给「发如雪」几分,那这些呢”, R.drawable.normal_4

,“更多为你推荐”,3,GridItem.TYPE_NORMAL));

values.add(new GridItem(“油管周杰伦热门单曲Top20”, “「周杰伦」的这些哥,你听了吗”, R.drawable.normal_5

,“更多为你推荐”,3,GridItem.TYPE_NORMAL));

return values;

}

class SpecialSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {

@Override

public int getSpanSize(int i) {

// 返回在数据中定义的SpanSize

GridItem gridItem = values.get(i);

return gridItem.getSpanSize();

}

}

class SmallHolder extends RecyclerAdapter.ViewHolder {

//… 代码省略,就是设置图片和文字的操作

// 小的Holder

}

class NormalHolder extends RecyclerAdapter.ViewHolder {

//… 中等的Holder

}

class SpecialHolder extends RecyclerAdapter.ViewHolder {

//… 横向大的Holder
SpanSize(int i) {

// 返回在数据中定义的SpanSize

GridItem gridItem = values.get(i);

return gridItem.getSpanSize();

}

}

class SmallHolder extends RecyclerAdapter.ViewHolder {

//… 代码省略,就是设置图片和文字的操作

// 小的Holder

}

class NormalHolder extends RecyclerAdapter.ViewHolder {

//… 中等的Holder

}

class SpecialHolder extends RecyclerAdapter.ViewHolder {

//… 横向大的Holder

上一篇:工厂模式之抽象工厂模式


下一篇:vue可拖拽组件vuedraggable