Android自定义ViewGroup之流式布局的实现

来源:互联网 发布:编程需要的电脑配置 编辑:程序博客网 时间:2024/05/01 11:08

前言:实现多元化的标签显示的页面,所有的子控件自动排版,类似各大网站的热搜效果!先贴上一张效果图供大家赏鉴!


先来说一下实现步骤:

一:定义一个容器:

      定义一个什么容器呢?存放子View的容器,这个容器可以是ViewGroup也可以Layout,我这里用的是ViewGroup

定义一个类继承于ViewGroup,实现其相应的构造方法,

二:对子View的宽高进行测量:
在onMeasure方法中对子View进行测量以及相应的判断

//测量子控件的宽高measureChildren(widthMeasureSpec, heightMeasureSpec);int wSize = MeasureSpec.getSize(widthMeasureSpec);int hSize = MeasureSpec.getSize(heightMeasureSpec);int wMode = MeasureSpec.getMode(widthMeasureSpec);int hMode = MeasureSpec.getMode(heightMeasureSpec);int aWidth = 0;//控件的总宽度int aHeight = 0;//控件的总高度int lineWidth = 0;//当前行的宽度int lineHeight = 0;//当前行的高度//遍历循环每个子控件for (int i = 0; i < getChildCount(); i++) {    View view = getChildAt(i);    MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams();    //当前控件所占的宽度    int width = view.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin;    //当前控件所占的高度    int height = view.getMeasuredHeight() + marginLayoutParams.bottomMargin + marginLayoutParams.topMargin;    //判断控件是否需要换行    if (lineWidth + width <= wSize) {        //宽度累加        lineWidth += width;        //高度取最大值        lineHeight = Math.max(lineHeight, height);    } else {        //需要换行        //将当前行的宽高情况,添加进总宽高中        aWidth = Math.max(aWidth, lineWidth);        aHeight += lineHeight;        //重新开启新的一行        lineWidth = width;        lineHeight = height;    }    if (i == getChildCount() - 1) {        //强最后一行的宽高情况添加进总宽高        aWidth = Math.max(aWidth, lineWidth);        aHeight += lineHeight;    }}Log.d("print", "onMeasure: " + aWidth + "     " + aHeight);setMeasuredDimension(        wMode == MeasureSpec.EXACTLY ? wSize : aWidth,        hMode == MeasureSpec.EXACTLY ? hSize : aHeight);

三:控制子View控件的位置的摆放:

设置每个子控件的摆放位置以及控制,在onLayout方法中去控制

int lineWidth = 0;//当前行的宽度int lineHeight = 0;//当前行的高度int aHeight = 0;//空间的总高度for (int i = 0; i < getChildCount(); i++) {    View view = getChildAt(i);    MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();    //当前空间的宽度和高度    int width = view.getMeasuredWidth();    int height = view.getMeasuredHeight();    if (lineWidth + width + layoutParams.leftMargin + layoutParams.rightMargin > getWidth()) {        //需要换行        aHeight += lineHeight;        lineWidth = 0;        lineHeight = 0;    }    l = layoutParams.leftMargin + lineWidth;    t = layoutParams.topMargin + aHeight;    r = layoutParams.rightMargin + width + lineWidth;    b = layoutParams.bottomMargin + aHeight + height;    //把当前控件的宽高数据加入到行的宽高数据中    lineWidth += width + layoutParams.leftMargin + layoutParams.rightMargin;    lineHeight = Math.max(lineHeight, height + layoutParams.topMargin + layoutParams.bottomMargin);    //摆放当前控件    view.layout(l, t, r, b);}

四:重写generateLayoutParams方法控制这个布局使用的布局参数:

默认是ViewGroup.LayoutParams

@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {    return new MarginLayoutParams(getContext(), attrs);}
五:XML文件中去引用

这个类放在最外层,将需要设置的子控件包裹就可以了!

2 0
原创粉丝点击