自定义ViewGroup-堆叠头像的点赞Layout

来源:互联网 发布:贵阳广电网络营业厅 编辑:程序博客网 时间:2024/06/06 00:22

简介

这里写图片描述

这样的点赞列表怎么样?之前做社区的时候也有类似的点赞列表,但是没有这样重叠,一个小小的改变,个人感觉逼格提高不少。

这个很有规则,就是后一个头像会覆盖一部分到前一个头像上,头像多了就像一串糖葫芦了。

这个实现起来不难,自定义ViewGroup,关键重写onLayout方法。我直接在AutoNewLineLayout基础上修改的。

关于自定义控件的基础知识可以看一看这个,整理的很详细:
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

2 0
原创粉丝点击