自定义ViewGroup,流式布局FlowLayout

来源:互联网 发布:怎么加入农村淘宝网 编辑:程序博客网 时间:2024/04/29 08:19

本文参考了【张鸿洋的博客】: Android 手把手教您自定义ViewGroup(一)和Android 自定义ViewGroup 实战篇 -> 实现FlowLayout

在很多应用里面,我们能看到类似于这样的流式
布局
用现有的控件我们实现这种动态适应的布局很麻烦,对于如何比较简单的去实现这种布局,就需要我们去自定义ViewGroup了

实现步骤

一、新建一个FlowLayout类,继承ViewGroup,并重写generateLayoutParams方法

重写generateLayoutParams是为了设置布局的LayoutParams,在这里,我们用系统的MarginLayoutParams就可以了

 //设置布局的LayoutParams,用系统的MarginLayoutParams就行    @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        return new MarginLayoutParams(getContext(), attrs);    }

二、重写onMeasure方法

重写onMeasure方法是为了根据子控件去计算布局的宽高,并进行设置

 //根据childView的高宽,计算布局的宽高,并进行设置    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //获取布局的父容器为它设置的测量模式和大小        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        //最后计算的布局宽高        int width = 0, height = 0;        //每一行的宽高        int lineWidth = 0, lineHeight = 0;        //循环childView        for (int i = 0, count = getChildCount(); i < count; i++) {            View view = getChildAt(i);            //计算当前childView的高和宽            measureChild(view, widthMeasureSpec, heightMeasureSpec);            //得到childView的LayoutParams            MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();            //得到childView所占的宽度和高度            int childWidth = view.getMeasuredWidth() + params.leftMargin + params.rightMargin;            if (childWidth > widthSize) {                params.width = widthSize - params.leftMargin - params.rightMargin;                view.setLayoutParams(params);                measureChild(view, widthMeasureSpec, heightMeasureSpec);            }            params = (MarginLayoutParams) view.getLayoutParams();            childWidth = view.getMeasuredWidth() + params.leftMargin + params.rightMargin;            int childHeight = view.getMeasuredHeight() + params.topMargin + params.bottomMargin;            //如果加入当前childView的宽度会超出父容器计算的宽度话,则需要开启新的一行,累加height            //否则累加当前行的宽高            if (lineWidth + childWidth > widthSize) {                //取宽度最大值                width = Math.max(lineWidth, childWidth);                //累加height                height += lineHeight;                //记录下一行的宽高                lineWidth = childWidth;                lineHeight = childHeight;            } else {                lineWidth += childWidth;                lineHeight = Math.max(lineHeight, childHeight);            }            //如果是最后一个,则将当前行的宽度与width做比较,累加height            if (i == count - 1) {                width = Math.max(lineWidth, width);                height += lineHeight;            }        }        //设置布局的宽高        setMeasuredDimension((widthMode == MeasureSpec.EXACTLY ? widthSize : width),                (heightMode == MeasureSpec.EXACTLY ? heightSize : height));    }

三、重写onLayout方法

重写onLayout方法是为了对布局所有的子控件进行重新排版,对他们的位置进行设置

//对所有的childView位置和大小进行设置    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        int widht = getWidth();        int height = getHeight();        //记录的高度        int recordHeight = 0;        //每行的宽高        int lineWidth = 0, lineHeight = 0;        //每个childView的坐标        int left = 0, top = 0, right = 0, bottom = 0;        //循环childView        for (int i = 0, count = getChildCount(); i < count; i++) {            View view = getChildAt(i);            //得到childView的LayoutParams            MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();            //得到childView宽高            int childWidth = view.getMeasuredWidth();            int childHeight = view.getMeasuredHeight();            if (childWidth + params.leftMargin + params.rightMargin + lineWidth > widht) {                recordHeight = recordHeight + lineHeight;                left = params.leftMargin;                right = left + childWidth;                top = recordHeight + params.topMargin;                bottom = top + childHeight;                lineWidth = childWidth + params.leftMargin + params.rightMargin;                lineHeight = childHeight + params.topMargin + params.bottomMargin;            } else {                left = lineWidth + params.leftMargin;                right = left + childWidth;                top = recordHeight + params.topMargin;                bottom = top + childHeight;                lineWidth = lineWidth + childWidth + params.leftMargin + params.rightMargin;                lineHeight = Math.max(lineHeight, childHeight + params.topMargin + params.bottomMargin);            }            view.layout(left, top, right, bottom);        }    }

四、代码中使用

至此,我们的流式布局已经写完,现在去用他进行布局
布局文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.krubo.flowlayout.MainActivity">    <com.krubo.flowlayout.FlowLayout        android:layout_width="match_parent"        android:layout_height="wrap_content">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="遍历所有的childView"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="用于设置allViews的值"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="根据"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="childView"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="所有的"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="遍历"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="到此完成了所有的childView的绘制区域的确定,到此,我们的FlowLayout的代码也结束了~~静下心来看一看是不是也不难"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="静下心"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="用于设置allViews的值"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="根据"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="childView"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="所有的"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="5dp"            android:background="#dddddd"            android:text="遍历"/>    </com.krubo.flowlayout.FlowLayout></LinearLayout>

运行后的效果图如下
这里写图片描述

0 0
原创粉丝点击