Android 瀑布流标签选择FlowLayout

1、说明

一个瀑布流标签的选择,支持单选与多选,其实就是一个自定义的ViewGroup。

2、演示

Android 瀑布流标签选择FlowLayout_第1张图片

3、代码

有人说,Android的自定义,玩的就是算法,其实真没错。自定义ViewGroup最重要就两个东西:onMeasure()方法和onLayout()方法;
思路大概就是:
在onMeasure()对子view宽高进行计算:
a:循环遍历所有的二级子view,计算子view的宽和高。当然宽和高要包括Margin值。
b:一行中的子view宽度之和比父view能给的最大宽度要大的话。就换到下一行。

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMax = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMax = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int widthNeed = 0;//需要的宽度
        int heightNeed = 0;//需要的高度
        int x_axle = 0;//位置坐标
        int y_axle = 0;
        int lineHeight = 0;//一行的高度
        View child;
        for (int i = 0; i < getChildCount(); i++) {
            child = getChildAt(i);

            if (child.getVisibility() == View.GONE) {
                continue;
            }

            child.measure(widthMeasureSpec, heightMeasureSpec);//通知child计算自己的宽高度
            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();//获取child的margin值
            int childHeight = child.getMeasuredHeight() + lp.topMargin+ lp.bottomMargin;

            //measure 时考虑把 margin 及  padding 也作为子视图大小的一部分
            measureChildWithMargins(child, widthMeasureSpec, 0,heightMeasureSpec, 0);

            int childWidth = child.getMeasuredWidth() + lp.leftMargin+ lp.rightMargin;
            if (x_axle + childWidth > widthMax) {//当一行的宽度不够时,本行高度和x轴都清零,y轴下移本行的高度
                y_axle += lineHeight;
                lineHeight = 0;
                x_axle = 0;
            }
            x_axle += childWidth;
            lineHeight = Math.max(lineHeight, childHeight);

            widthNeed = Math.max(widthNeed, x_axle);
            heightNeed = Math.max(heightNeed, y_axle + lineHeight);
        }
        setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthMax
                : widthNeed, heightMode == MeasureSpec.EXACTLY ? heightMax
                : heightNeed);
    }

在onLayout()中根据计算的结果,来摆放子view。

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int widthMax = getWidth();
        int x_axle, y_axle;
        x_axle = 0;//位置坐标
        y_axle = 0;
        View child;
        int left = 0;//child左上角坐标点
        int top = 0;
        int lineHeight = 0;
        for (int i = 0; i < getChildCount(); i++) {
            child = getChildAt(i);
            if (child.getVisibility() == View.GONE) {
                continue;
            }
            MarginLayoutParams lp = (MarginLayoutParams) child
                    .getLayoutParams();
            int childWidth = child.getMeasuredWidth() + lp.leftMargin
                    + lp.rightMargin;
            int childHeight = child.getMeasuredHeight() + lp.topMargin
                    + lp.bottomMargin;
            if (x_axle + childWidth > widthMax) {// 换行处理
                y_axle += lineHeight;
                x_axle = 0;
                lineHeight = 0;
            }
            left = x_axle + lp.leftMargin;
            top = y_axle + lp.topMargin;
            //在合适的位置摆放child
            child.layout(left, top, left + child.getMeasuredWidth(), top
                    + child.getMeasuredHeight());

            x_axle += childWidth;
            lineHeight = Math.max(lineHeight, childHeight);
        }
    }

代码不是多,也不难,无非就是计算,很容易看懂。后面的单选和多选就只是逻辑处理了。代码中是用的TextView作为的子view。当然这里可以是任何的view。
demo下载地址:http://download.csdn.net/detail/u010886975/9693799

你可能感兴趣的:(自定义view)