Android自定义ViewGroup实现堆叠头像的点赞Layout
程序员文章站
2024-02-10 12:47:28
简介
这样的点赞列表怎么样?之前做社区的时候也有类似的点赞列表,但是没有这样重叠,一个小小的改变,个人感觉逼格提高不少。
这个很有规则,就是后一个头像会覆盖一部分到...
简介
这样的点赞列表怎么样?之前做社区的时候也有类似的点赞列表,但是没有这样重叠,一个小小的改变,个人感觉逼格提高不少。
这个很有规则,就是后一个头像会覆盖一部分到前一个头像上,头像多了就像一串糖葫芦了。
这个实现起来不难,自定义viewgroup,关键重写onlayout方法。
关于自定义控件的基础知识可以看一看这个,整理的很详细: https://github.com/gcssloop/androidnote
实现
自定义属性
属性名 | 说明 | 默认值 |
---|---|---|
vertivalspace | 行距 | 4dp |
pilewidth | 重叠宽度 | 10dp |
onmeasure方法,每行的宽度不再是child的宽度和了,而是要减掉重叠部分的宽度和
@override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); int widthspecmode = measurespec.getmode(widthmeasurespec); int widthspecsize = measurespec.getsize(widthmeasurespec); int heightspecmode = measurespec.getmode(heightmeasurespec); int heightspecsize = measurespec.getsize(heightmeasurespec); //at_most int width = 0; int height = 0; int rawwidth = 0;//当前行总宽度 int rawheight = 0;// 当前行高 int rowindex = 0;//当前行位置 int count = getchildcount(); for (int i = 0; i < count; i++) { view child = getchildat(i); if(child.getvisibility() == gone){ if(i == count - 1){ //最后一个child height += rawheight; width = math.max(width, rawwidth); } continue; } //这里调用measurechildwithmargins 而不是measurechild measurechildwithmargins(child, widthmeasurespec, 0, heightmeasurespec, 0); marginlayoutparams lp = (marginlayoutparams) child.getlayoutparams(); int childwidth = child.getmeasuredwidth() + lp.leftmargin + lp.rightmargin; int childheight = child.getmeasuredheight() + lp.topmargin + lp.bottommargin; if(rawwidth + childwidth - (rowindex > 0 ? pilewidth : 0)> widthspecsize - getpaddingleft() - getpaddingright()){ //换行 width = math.max(width, rawwidth); rawwidth = childwidth; height += rawheight + vertivalspace; rawheight = childheight; rowindex = 0; } else { rawwidth += childwidth; if(rowindex > 0){ rawwidth -= pilewidth; } rawheight = math.max(rawheight, childheight); } if(i == count - 1){ width = math.max(rawwidth, width); height += rawheight; } rowindex++; } setmeasureddimension( widthspecmode == measurespec.exactly ? widthspecsize : width + getpaddingleft() + getpaddingright(), heightspecmode == measurespec.exactly ? heightspecsize : height + getpaddingtop() + getpaddingbottom() ); }
onlayout 每一行,第一个正常放,之后的重叠放
@override protected void onlayout(boolean changed, int l, int t, int r, int b) { int viewwidth = r - l; int leftoffset = getpaddingleft(); int topoffset = getpaddingtop(); int rowmaxheight = 0; int rowindex = 0;//当前行位置 view childview; for( int w = 0, count = getchildcount(); w < count; w++ ){ childview = getchildat(w); if(childview.getvisibility() == gone) continue; marginlayoutparams lp = (marginlayoutparams) childview.getlayoutparams(); // 如果加上当前子view的宽度后超过了viewgroup的宽度,就换行 int occupywidth = lp.leftmargin + childview.getmeasuredwidth() + lp.rightmargin; if(leftoffset + occupywidth + getpaddingright() > viewwidth){ leftoffset = getpaddingleft(); // 回到最左边 topoffset += rowmaxheight + vertivalspace; // 换行 rowmaxheight = 0; rowindex = 0; } int left = leftoffset + lp.leftmargin; int top = topoffset + lp.topmargin; int right = leftoffset+ lp.leftmargin + childview.getmeasuredwidth(); int bottom = topoffset + lp.topmargin + childview.getmeasuredheight(); childview.layout(left, top, right, bottom); // 横向偏移 leftoffset += occupywidth; // 试图更新本行最高view的高度 int occupyheight = lp.topmargin + childview.getmeasuredheight() + lp.bottommargin; if(rowindex != count - 1){ leftoffset -= pilewidth;//这里控制重叠位置 } rowmaxheight = math.max(rowmaxheight, occupyheight); rowindex++; } }
效果图
因为这个一般只会显示一行,所以暂时没有通过setadapter方式去设置数据源。
下载
https://github.com/linechen/pilelayout
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。