1、流式布局特点、应用场景。
2、自定义ViewGroup
(1)onMeasure:测量子View的宽和高,设置自己的宽和高。
(2)onLayout:设置子View的位置。

onMeasure:根据子View的布局文件,为子View设置测量模式和测量值。

测量 = 测量模式 + 测量值;
测量模式:3种。
(1)EXACTLY:100dp , match_parent。
(2)AT_MOST: wrap_content。
(3)UNSPCIFIED:子控件想要多大就多大,很少见。

ViewGroup - LayoutParams

FlowLayout - MarginLayoutParams

子View.getLayoutParams(); -> LinearLayout.LayoutParams

  import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

// Source --- Generate Constructors from Superdass... ,生成三个构造方法。
public class FlowLayout extends ViewGroup { // 存储所有的View 一行一行的存储
// 比如:一共三行 List就是3。一行有10个那么List<View> 就是10
private List<List<View>> mAllViews = new ArrayList<List<View>>();
// 每一行的高度
private List<Integer> mLineHeight = new ArrayList<Integer>(); // 使用控件,及其实行,而且用了自定义的属性
public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 这样所有的逻辑就全部可以卸载这个里面去
} // 用到控件的属性(非自定义)
public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0); // 调用三个构造参数方法
} // new一个控件的时候,我们传入一个上下文。
public FlowLayout(Context context) {
this(context, null); // 调用两个构造参数方法
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 宽度(测量值) 容器的宽度
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
// 宽度(测量模式)
// modeWidth == MeasureSpec.AT_MOST 用于判断
int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
int modeHeight = MeasureSpec.getMode(heightMeasureSpec); // wrap_content (自己去计算)
int width = 0;
int height = 0; // 记录每一行的宽度与高度
int lineWidth = 0;
int lineHeight = 0; // 得到内部元素的个数
int cCount = getChildCount(); for (int i = 0; i < cCount; i++) {
View child = getChildAt(i);
// 测量子View的宽和高
measureChild(child, widthMeasureSpec, heightMeasureSpec);
// 得到LayoutParams
MarginLayoutParams lp = (MarginLayoutParams) child
.getLayoutParams(); // 子View占据的宽度
int childWidth = child.getMeasuredWidth() + lp.leftMargin
+ lp.rightMargin;
// 子View占据的高度
int childHeight = child.getMeasuredHeight() + lp.topMargin
+ lp.bottomMargin; // 换行
// lineWidth:上一行的宽度 + childWidth:当前控件的宽度。
// sizeWidth:当前容器的宽度。
// " - getPaddingLeft()- getPaddingRight() "
// 是针对 android:padding="20dp"进行的。
if (lineWidth + childWidth > sizeWidth - getPaddingLeft()
- getPaddingRight()) {
// 对比得到最大的宽度
width = Math.max(width, lineWidth);
// 重置lineWidth
lineWidth = childWidth;
// 记录行高
height += lineHeight;
lineHeight = childHeight;
} else { // 未换行
// 叠加行宽
lineWidth += childWidth;
// 得到当前行最大的高度
lineHeight = Math.max(lineHeight, childHeight);
}
// 最后一个控件
if (i == cCount - 1) {
width = Math.max(lineWidth, width);
height += lineHeight;
}
} Log.e("TAG", "sizeWidth = " + sizeWidth);
Log.e("TAG", "sizeHeight = " + sizeHeight); // 判断测量模式
// " + getPaddingLeft() + getPaddingRight() "
// 是针对 android:padding="20dp"进行的。
setMeasuredDimension(
//
modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width
+ getPaddingLeft() + getPaddingRight(),
modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height
+ getPaddingTop() + getPaddingBottom()//
); } @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mAllViews.clear();
mLineHeight.clear(); // 当前ViewGroup的宽度
int width = getWidth(); int lineWidth = 0;
int lineHeight = 0; List<View> lineViews = new ArrayList<View>(); int cCount = getChildCount(); for (int i = 0; i < cCount; i++) {
View child = getChildAt(i);
MarginLayoutParams lp = (MarginLayoutParams) child
.getLayoutParams(); int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight(); // 如果需要换行
// 当前行的宽度 + 当前列的宽度 + lp.leftMargin + lp.rightMargin
// " - getPaddingLeft() - getPaddingRight() "
// 是针对 android:padding="20dp"进行的。
if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width
- getPaddingLeft() - getPaddingRight()) {
// 记录LineHeight
mLineHeight.add(lineHeight);
// 记录当前行的Views
mAllViews.add(lineViews); // 重置我们的行宽和行高
lineWidth = 0;
lineHeight = childHeight + lp.topMargin + lp.bottomMargin;
// 重置我们的View集合
lineViews = new ArrayList<View>();
}
lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
lineHeight = Math.max(lineHeight, childHeight + lp.topMargin
+ lp.bottomMargin);
lineViews.add(child); }// for end
// 处理最后一行
mLineHeight.add(lineHeight);
mAllViews.add(lineViews); // 设置子View的位置
// 是针对 android:padding进行的。
// 所以不能给left和top设置0。
int left = getPaddingLeft();
int top = getPaddingTop(); // 行数
int lineNum = mAllViews.size(); for (int i = 0; i < lineNum; i++) {
// 当前行的所有的View
lineViews = mAllViews.get(i);
lineHeight = mLineHeight.get(i); for (int j = 0; j < lineViews.size(); j++) {
View child = lineViews.get(j);
// 判断child的状态
if (child.getVisibility() == View.GONE) {
continue;
} MarginLayoutParams lp = (MarginLayoutParams) child
.getLayoutParams(); int lc = left + lp.leftMargin;
int tc = top + lp.topMargin;
int rc = lc + child.getMeasuredWidth();
int bc = tc + child.getMeasuredHeight(); // 为子View进行布局
child.layout(lc, tc, rc, bc); left += child.getMeasuredWidth() + lp.leftMargin
+ lp.rightMargin;
}
// 每次循环完一行后
// 是针对 android:padding进行的。
// 所以不能给left设置0。
left = getPaddingLeft();
top += lineHeight; // 累加
} } /**
* 与当前ViewGroup对应的LayoutParams
*/
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
} }
<RelativeLayout 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" > <com.imooc.view.FlowLayout
android:id="@+id/id_flowlayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#E5E5F5"
android:padding="20dp" >
</com.imooc.view.FlowLayout> </RelativeLayout>
 import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.widget.TextView;
import com.imooc.view.FlowLayout; public class MainActivity extends Activity { private String[] mVals = new String[] { "Hello", "Android", "Weclome Hi ",
"Button", "TextView", "Hello", "Android", "Weclome",
"Button ImageView", "TextView", "Helloworld", "Android",
"Weclome Hello", "Button Text", "TextView" }; private FlowLayout mFlowLayout; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mFlowLayout = (FlowLayout) findViewById(R.id.id_flowlayout); initData();
} public void initData() {
// for (int i = 0; i < mVals.length; i++)
// {
// Button btn = new Button(this);
//
// MarginLayoutParams lp = new MarginLayoutParams(
// MarginLayoutParams.WRAP_CONTENT,
// MarginLayoutParams.WRAP_CONTENT);
//
// btn.setText(mVals[i]);
// mFlowLayout.addView(btn, lp);
// }
LayoutInflater mInflater = LayoutInflater.from(this);
for (int i = 0; i < mVals.length; i++) {
TextView tv = (TextView) mInflater.inflate(R.layout.tv,
mFlowLayout, false);
tv.setText(mVals[i]);
mFlowLayout.addView(tv);
}
}
}
 <?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:background="@drawable/tv_bg"
android:textColor="#5BC4ED"
android:text="Helloworld" >
</TextView>

@drawable/tv_bg

 <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#ffffff" />
<corners android:radius="30dp" />
<padding
android:bottom="2dp"
android:left="10dp"
android:right="10dp"
android:top="2dp" />
</shape>

DEMO下载地址:http://download.csdn.net/detail/androidsj/9446937

Android中流式布局和热门标签的更多相关文章

  1. Android控件进阶-自定义流式布局和热门标签控件

    技术:Android+java   概述 在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧,类 ...

  2. android流式布局、待办事项应用、贝塞尔曲线、MVP+Rxjava+Retrofit、艺术图片应用等源码

    Android精选源码 android模仿淘宝首页效果源码 一款艺术图片应用,采用T-MVVM打造 Android MVP + RxJava + Retrofit项目 android流式布局实现热门标 ...

  3. Android流式布局实现

    查看我的所有开源项目[开源实验室] 欢迎增加我的QQ群:[201055521],本博客client下载[请点击] 摘要 新项目用到了一种全新布局----Android标签流式布局的功能,正好一直说给大 ...

  4. android -------- 流式布局,支持单选、多选等

    最近开发中有流式标签这个功能,网上学了下,来分享一下 Android 流式布局,支持单选.多选等,适合用于产品标签等. 效果图: 用法: dependencies { compile 'com.hym ...

  5. android 自定义流布局。实现热门标签。开源库SimpleFlowLayout

    前言 实际项目中需要实现一个 热门搜索 的栏目,类似下图: 由于 子项(子view) 中的文字是可变的,一行能显示的 子项 的个数也无法确定.需要支持自动换行和计算位置. 开源类库 我自己写了个 自定 ...

  6. 含有过滤功能的android流式布局

    FilterFlowLayout 含有过滤功能的流式布局, 參考FlowLayout 能够去除宽度不在范围(比例或真实值)内的子view 能够设置最大行数 能够加入组件间水平间距 能够加入行间距 系统 ...

  7. Android流式布局控件

    1,自定义flowlayout代码 package com.hyang.administrator.studentproject.widget; import android.content.Cont ...

  8. Android 自定义View修炼-Android中常见的热门标签的流式布局的实现

    一.概述:在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出哈) 类似的 ...

  9. Android 自动换行流式布局的RadioGroup

    效果图 用法 使用FlowRadioGroup代替RadioGroup 代码 import android.content.Context; import android.util.Attribute ...

随机推荐

  1. tomcat禁用webdav

    在tomcat的web.xml,以及自己项目的web.xml中,均需添加以下内容: <security-constraint> <web-resource-collection> ...

  2. 自定义基于XML的验证器

    a.编写一个类,继承FieldValidatorSupport类. b.在public void validate(Object object)编写你的验证逻辑 不符合要求的就向fieldErrors ...

  3. jsp 普通变量与jQuery变量之间的转换

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  4. AAAA block

    [self AAAA:^(BOOL isSuccessed, id userInfo, NSString *errorMsg) { NSLog(@"AAAA: %d, userInfo: % ...

  5. HDOJ 5418 Victor and World 状压DP

    水状压DP Victor and World Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java ...

  6. python-创建一个登录判断的函数

    方法一def account_login(): password = input('Password:') if password == '12345': print('Login success!' ...

  7. unity, access standard shared emission by script

    unity 5.1.1f1 personal 用下面方法在脚本中设置standard shader的emssion: gameObject.GetComponent<MeshRenderer&g ...

  8. 简单记录一次ORA-00600 kcratr_nab_less_than_odr

    当前具体报错已经没有了,仅仅有对应图.參考EYGLE一篇文章中数据: 1.故障现象 数据库版本号11G,错误类似下面: ORA-00600: 内部错误代码, 參数: [kcratr_nab_less_ ...

  9. Objective-C之@protocol

    转自:http://www.cnblogs.com/hxxy2003/archive/2011/10/24/2222838.html @protocol是Objective-C中的接口定义方式,也就是 ...

  10. H3C-WA2210升级

    前几天升级了2210固件,做个记录 首先吐槽一点:华为官方给出的公共下载账号yx800根本没用..下不了官方提供的固件资料 组网准备: 升级之前要先看看原机版本(dis ver): 在升级版本之前,请 ...