package com.loaderman.customviewdemo;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup; public class FlowLayout extends ViewGroup {
public FlowLayout(Context context) {
super(context);
} public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
} public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} /**
* 父容器生成 子view 的布局LayoutParams;
* 一句话道出LayoutParams的本质:LayoutParams是Layout提供给其中的Children使用的。
* 如果要自定义ViewGroup支持子控件的layout_margin参数,则自定义的ViewGroup类必须重载generateLayoutParams()函数,
* 并且在该函数中返回一个ViewGroup.MarginLayoutParams派生类对象,这样才能使用margin参数。
*/
@Override
protected LayoutParams generateLayoutParams(
LayoutParams p)
{
return new MarginLayoutParams(p);
} @Override
public LayoutParams generateLayoutParams(AttributeSet attrs)
{
return new MarginLayoutParams(getContext(), attrs);
} @Override
protected LayoutParams generateDefaultLayoutParams()
{
return new MarginLayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec); int lineWidth = 0;
int lineHeight = 0;
int height = 0;
int width = 0;
int count = getChildCount();
for (int i=0;i<count;i++){
View child = getChildAt(i);
measureChild(child,widthMeasureSpec,heightMeasureSpec);
//如果忘记重写generateLayoutParams,则hild.getLayoutParams()将不是MarginLayoutParams的实例
//在强制转换时就会出错,此时我们把左右间距设置为0,但由于在计算布局宽高时没有加上间距值,就是计算出的宽高要比实际小,所以是onLayout时就会出错
MarginLayoutParams lp = null;
if (child.getLayoutParams() instanceof MarginLayoutParams) {
lp = (MarginLayoutParams) child
.getLayoutParams();
}else{
lp = new MarginLayoutParams(0,0);
}
int childWidth = child.getMeasuredWidth() + lp.leftMargin +lp.rightMargin;
int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; if (lineWidth + childWidth > measureWidth){
//需要换行
width = Math.max(lineWidth,width);
height += lineHeight;
//因为由于盛不下当前控件,而将此控件调到下一行,所以将此控件的高度和宽度初始化给lineHeight、lineWidth
lineHeight = childHeight;
lineWidth = childWidth;
}else{
// 否则累加值lineWidth,lineHeight取最大高度
lineHeight = Math.max(lineHeight,childHeight);
lineWidth += childWidth;
} //最后一行是不会超出width范围的,所以要单独处理
if (i == count -1){
height += lineHeight;
width = Math.max(width,lineWidth);
} }
//当属性是MeasureSpec.EXACTLY时,那么它的高度就是确定的,
// 只有当是wrap_content时,根据内部控件的大小来确定它的大小时,大小是不确定的,属性是AT_MOST,此时,就需要我们自己计算它的应当的大小,并设置进去
setMeasuredDimension((measureWidthMode == MeasureSpec.EXACTLY) ? measureWidth
: width, (measureHeightMode == MeasureSpec.EXACTLY) ? measureHeight
: height);
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
int lineWidth = 0;
int lineHeight = 0;
int top=0,left=0;
for (int i=0; i<count;i++){
View child = getChildAt(i);
MarginLayoutParams lp = (MarginLayoutParams) child
.getLayoutParams();
int childWidth = child.getMeasuredWidth()+lp.leftMargin+lp.rightMargin;
int childHeight = child.getMeasuredHeight()+lp.topMargin+lp.bottomMargin; if (childWidth + lineWidth >getMeasuredWidth()){
//如果换行,当前控件将跑到下一行,从最左边开始,所以left就是0,而top则需要加上上一行的行高,才是这个控件的top点;
top += lineHeight;
left = 0;
//同样,重新初始化lineHeight和lineWidth
lineHeight = childHeight;
lineWidth = childWidth;
}else{
lineHeight = Math.max(lineHeight,childHeight);
lineWidth += childWidth;
}
//计算childView的left,top,right,bottom
int lc = left + lp.leftMargin;
int tc = top + lp.topMargin;
int rc =lc + child.getMeasuredWidth();
int bc = tc + child.getMeasuredHeight();
child.layout(lc, tc, rc, bc);//布局控件
//将left置为下一子控件的起始点
left+=childWidth;
} } }
<?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="wrap_content"
android:background="#ff00ff"
tools:context=".MainActivity"> <com.loaderman.customviewdemo.FlowLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
style="@style/text_flag_01"
android:background="@drawable/flag_03"
android:text="Welcome"
android:textColor="@android:color/white" /> <TextView
style="@style/text_flag_01"
android:background="@drawable/flag_03"
android:text="IT工程师"
android:textColor="@android:color/white" /> <TextView
style="@style/text_flag_01"
android:background="@drawable/flag_03"
android:text="我真是可以的"
android:textColor="@android:color/white" /> <TextView
style="@style/text_flag_01"
android:background="@drawable/flag_03"
android:text="你觉得呢"
android:textColor="@android:color/white" /> <TextView
style="@style/text_flag_01"
android:background="@drawable/flag_03"
android:text="不要只知道挣钱"
android:textColor="@android:color/white" /> <TextView
style="@style/text_flag_01"
android:background="@drawable/flag_03"
android:text="努力ing"
android:textColor="@android:color/white" /> <TextView
style="@style/text_flag_01"
android:background="@drawable/flag_03"
android:text="I thick i can"
android:textColor="@android:color/white" />
</com.loaderman.customviewdemo.FlowLayout>
</LinearLayout>

效果:

FlowLayout实现的更多相关文章

  1. 【Java布局】FlowLayout布局时设定组件大小

    默认的JPanel中,采用的是FlowLayout布局 下面是api中的定义: JPanel(boolean isDoubleBuffered)           创建具有 FlowLayout 和 ...

  2. Android自定义实现FlowLayout

    实现FlowLayout 何为FlowLayout,如果对Java的Swing比较熟悉的话一定不会陌生,就是控件根据ViewGroup的宽,自动的往右添加,如果当前行剩余空间不足,则自动添加到下一行. ...

  3. 转:Java图形化界面设计——布局管理器之FlowLayout(流式布局)其他请参考转载出处网址

    http://blog.csdn.net/liujun13579/article/details/7771191 前文讲解了JFrame.JPanel,其中已经涉及到了空布局的使用.Java虽然可以以 ...

  4. Java SE (1)之 JFrame 组件 FlowLayout 布局

    package com.sunzhiyan; import java.awt.*; import java.awt.event.*; import javax.swing.*; public clas ...

  5. iOS流布局UICollectionView使用FlowLayout进行更灵活布局

    一.引言 前面的博客介绍了UICollectionView的相关方法和其协议中的方法,但对布局的管理类UICollectionViewFlowLayout没有着重探讨,这篇博客介绍关于布局的相关设置和 ...

  6. Java图形化界面设计——布局管理器之FlowLayout(流式布局)

    一.布局管理器所属类包 所属类包 布局管理器名称 说明 Java.awt FlowLayout(流式布局) 组件按照加入的先后顺序按照设置的对齐方式从左向右排列,一行排满到下一行开始继续排列 Bord ...

  7. 5、Java Swing布局管理器(FlowLayout、BorderLayout、CardLayout、BoxLayout、GirdBagLayout 和 GirdLayout)

    5.Java-Swing常用布局管理器       应用布局管理器都属于相对布局,各组件位置可随界面大小而相应改变,不变的只是其相对位置,布局管理器比较难以控制,一般只在界面大小需要改是才用,但即使这 ...

  8. Swing-布局管理器之FlowLayout(流式布局)-入门

    FlowLayout应该是Swing布局管理器学习中最简单.最基础的一个.所谓流式,就是内部控件像水流一样,从前到后按顺序水平排列,直到达到容器的宽度时跳转到第二行.既然是水平排列,那么就存在三种基本 ...

  9. FlowLayout OnSizeChanged

    在FlowLayout里加了20个控件,当窗口变化时,改变这20个控件的宽高,结果发现在直接点最大化时, 计算不正确导致自身的滚动条出不来.把改变大小的代码直接添加Form窗口的onSizeChagn ...

  10. Android -- 自定义ViewGroup实现FlowLayout效果

    1,在开发的时候,常在我们的需求中会有这种效果,添加一个商品的一些热门标签,效果图如下: 2,从上面效果可以看得出来,这是一个自定义的ViewGroup,然后实现换行效果,让我们一起来实现一下 自定义 ...

随机推荐

  1. linux网络编程之socket编程(十)

    今天继续socket编程的学习,最近晚上睡觉都没有发热,没有暖气的日子还是种煎熬,快乐的十一也已经走来,幸福有暖气的日子也快啦,好了,回到正题~ ①close终止了数据传送的两个方向. ②shutdo ...

  2. 1203 forms组件

    目录 昨日内容 多对多三种创建方式 1.全自动 好处 缺点 2.纯手动 好处 缺点 3.半自动through='',through_fields=(外键字段) 好处 缺点 forms组件 1.简单引入 ...

  3. 1121 Django操作

    目录 Django前戏 一.课程导读 1.web应用 2.c/s b/s 架构 3.Python Web框架 二.原生socket服务 三.http协议 什么是http协议 四大特性 http工作原理 ...

  4. 浅析 array_map array_walk

    map    主要是为了得到你的回调函数处理后的新数组,要的是结果. walk   主要是对每个参数都使用一次你的回调函数,要的是处理的过程. walk   可以认为提供额外参数给回调函数,map不可 ...

  5. Git报错:Please tell me who you are.

    Git在提交的时候报错 Please tell me who you are. 报错 Please tell me who you are. 具体如下: 原因:明确报错.请告诉我你是谁.意思是你在提交 ...

  6. vue 安装 ‘node-sass’ 运行报错:ERROR in Cannot find module 'node-sass'

    好像是由于cnpm安装导致.执行下面的安装代码,或者使用npm 安装node-sass cnpm install node-sass@latest

  7. python中的函数、生成器的工作原理

    1.python中函数的工作原理 def foo(): bar() def bar(): pass python的解释器,也就是python.exe(c编写)会用PyEval_EvalFramEx(c ...

  8. Learning Spark (Python版) 学习笔记(一)----RDD 基本概念与命令

    <Learning Spark>这本书算是Spark入门的必读书了,中文版是<Spark快速大数据分析>,不过豆瓣书评很有意思的是,英文原版评分7.4,评论都说入门而已深入不足 ...

  9. 005_硬件基础电路_PCB安规设计规范

    包含两个文件:讲解pcb绘制过程中的安规要求 002_2_PCB安规设计规范(原创-绝对经典全面-玩转高压PCB设计)总结 002_3_电气间隙和爬电距离规定 链接:https://pan.baidu ...

  10. [APIO2012]派遣 左偏树

    P1552 [APIO2012]派遣 题面 考虑枚举每个节点作为管理者,计算所获得的满意程度以更新答案.对于每个节点的计算,贪心,维护一个大根堆,每次弹出薪水最大的人.这里注意,一旦一个人被弹出,那么 ...