先上效果图:2种情况:1、显示很多行,一屏放不下;2、显示指定行数(以2行为例)
1、
2、
以第一种情况讲解,如果用到第二种情况,参见FlowLayout文件中的TODO标记上的讲解。如果一行已经放进来3个数据了,第4要放进来,就超出屏幕宽度,不放进来,就有留白。这时候,处理方法是:不把第4个数据放进来。把留白平分3份,给之前的每个数据加一点宽度,这样好看。
注:这里用了随机生成颜色,每次重新加载,看到的颜色都不一样
实现步骤:
1、将创建FlowLayout文件,将下面源码复制进去
package com.chen.demo;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
/*
* 整体思路: 自定义FlowLayout: 1.根据list的size往里面动态添加TextView 2.定义变量:
* a.horizontalSpacing:子view间的水平间距 b.verticalSpacing: line间的垂直间距
* c.lineList:用于存放每个line 3.定义Line类:用来记录当前行中的子view,并且提供width和height;
* width:表示所有子view的宽加上中间的空隙值,在每次添加子view的时候都会更新 height:始终等于当前行中最高子view的高度
* 4.遍历所有子view过程并判断如下: a.先测量当前childView,保证能获取到宽度和高度
* b.如果当前line中还没子view,则直接放入,不用判断长度
* c.当前line中已经有子view的情况:如果line的宽度+horizontalSpacing+child.getMeasuredWidth
* 大于当前总宽度则立即存储当前line,然后重新new Line(),并将子view加入到new的Line中;
* 如果不大于总宽度,则将当前childView放入line中;
* d.注意:每次往line中放子view的时候都需要判断当前子view是否是最后一个;如果是最后一个子 view了,那么久需要将当前line存储,
*
* 5.依次摆放lineList中每个line中保存的子view: a.遍历lineList,取出当前line;
* b.遍历当前line,取出当前childView;
* c.如果line是第一行:对childView进行摆放如下:如果childView是第一个,则left是getPaddingLeft,
* top是getPaddingTop;right是left+自身的宽,bottom是top+自身的高;
* 如果childView不是第一个,则取出前一个子view(记录为lastChild);则当前childView的left是
* lastChild的right+horizontalSpacing;top和lastChild一样,right是自身的left+自身的宽;
* bottom是和lastChild一样;
* d.如果当前line是第二行,则子view摆放的top需要在getPaddingTop的基础上+line的高度+verticalSpacing;
* e.最后,由于每行的子view摆放出来之后会有剩余的空间,所以获取剩余的空间,然后除以
* 子view的数量,得到每个子view应该重新分配的值,对他们的宽重新赋值,并且这个赋值的 操作是在摆放子view之前,因为摆放的时候用到了他们的宽度
*/
public class FlowLayout extends ViewGroup {
/**
* 默认的间距
*/
private int DEFAULT_SPACING = 25;
/**
* 子view水平方向的间距
*/
private int horizontalSpacing = 40;
/**
* 每行之间的垂直间距
*/
private int verticalSpacing = 60;
/**
* 用来保存每一行line
*/
private ArrayList<Line> lineList = new ArrayList<Line>();
/**
* 有多少行
*/
int lineNumber = 0;
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FlowLayout(Context context) {
super(context);
}
/**
* 分行和测量FlowLayout的宽高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
lineList.clear();// 开始分行前先清空之前的list
int width = MeasureSpec.getSize(widthMeasureSpec);// 获得控件的宽度,是包含paddingLeft和paddingRight
// 这个宽才是我们需要比较用的宽
int noPaddingWidth = width - getPaddingLeft() - getPaddingRight();// 获取除去padding后的width
int height = MeasureSpec.getSize(0);// 获取控件的高度
Line line = null;// 声明为局部变量
for (