Android流式布局实现
查看我的所有开源项目【开源实验室】
欢迎增加我的QQ群:【201055521】,本博客client下载【请点击】
摘要
新项目用到了一种全新布局————Android标签流式布局的功能,正好一直说给大家讲自己定义控件的实现,今天就为大家讲一种android流式布局的实现。
本文原创,转载请注明地址:http://blog.kymjs.com/
正文
在日常的app使用中,我们会在android 的app中看见热门标签等自己主动换行的流式布局,今天。我们就来看看怎样自己定义一个相似热门标签那样的流式布局吧(源代码下载在以下最后给出)
这个控件并非我实现的,代码是从网上搜流式布局找到的。我仅仅是为大家解说一下实现过程以及原理。
先看代码
public class FlowLayout extends ViewGroup {
private float mVerticalSpacing; //每个item纵向间距
private float mHorizontalSpacing; //每个item横向间距
public FlowLayout(Context context) {
super(context);
}
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setHorizontalSpacing(float pixelSize) {
mHorizontalSpacing = pixelSize;
}
public void setVerticalSpacing(float pixelSize) {
mVerticalSpacing = pixelSize;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int selfWidth = resolveSize(0, widthMeasureSpec);
int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop();
int paddingRight = getPaddingRight();
int paddingBottom = getPaddingBottom();
int childLeft = paddingLeft;
int childTop = paddingTop;
int lineHeight = 0;
//通过计算每个子控件的高度,得到自己的高度
for (int i = 0, childCount = getChildCount(); i < childCount; ++i) {
View childView = getChildAt(i);
LayoutParams childLayoutParams = childView.getLayoutParams();
childView.measure(
getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight,
childLayoutParams.width),
getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom,
childLayoutParams.height));
int childWidth = childView.getMeasuredWidth();
int childHeight = childView.getMeasuredHeight();
lineHeight = Math.max(childHeight, lineHeight);
if (childLeft + childWidth + paddingRight > selfWidth) {
childLeft = paddingLeft;
childTop += mVerticalSpacing + lineHeight;
lineHeight = childHeight;
} else {
childLeft += childWidth + mHorizontalSpacing;
}
}
int wantedHeight = childTop + lineHeight + paddingBottom;
setMeasuredDimension(selfWidth, resolveSize(wantedHeight, heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int myWidth = r - l;
int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop();
int paddingRight = getPaddingRight();
int childLeft = paddingLeft;
int childTop = paddingTop;
int lineHeight = 0;
//依据子控件的宽高,计算子控件应该出现的位置。
for (int i = 0, childCount = getChildCount(); i < childCount; ++i) {
View childView = getChildAt(i);
if (childView.getVisibility() == View.GONE) {
continue;
}
int childWidth = childView.getMeasuredWidth();
int childHeight = childView.getMeasuredHeight();
lineHeight = Math.max(childHeight, lineHeight);
if (childLeft + childWidth + paddingRight > myWidth) {
childLeft = paddingLeft;
childTop += mVerticalSpacing + lineHeight;
lineHeight = childHeight;
}
childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
childLeft += childWidth + mHorizontalSpacing;
}
}
}
从控件创建过程说起
- 当这个流式布局在被载入如内存并显示在屏幕上这一过程中。首先会调用view.measure(w,h)这种方法,表示測量view的宽度与高度。当中參数w与h分别表示这个控件的父控件的宽高。
- 在view.measure()方法的调用过程中又会调用view本身的一个回调方法,onMeasure(),这个是view自身的一个回调方法。用于让开发人员在自己定义View的时候又一次计算自身的大小。通常会在这种方法中循环遍历,计算出这个控件的所有子孙控件的宽高。
- 在View的宽高计算完毕以后,考虑将这个控件显示到屏幕的指定位置上,此时view的onLayout()方法会被调用。
一般同一时候会在这种方法中计算出所有子孙控件在这个控件中的位置。
可能基本流程有些枯燥,接下来结合代码看看。
流布局的实现
看到onMeasure()方法中的这段:
//通过计算每个子控件的高度,得到自己的高度
for (int i = 0, childCount = getChildCount(); i < childCount; ++i) {
View childView = getChildAt(i);
LayoutParams childLayoutParams = childView.getLayoutParams();
childView.measure(
getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight,
childLayoutParams.width),
getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom,
childLayoutParams.height));
int childWidth = childView.getMeasuredWidth();
int childHeight = childView.getMeasuredHeight();
lineHeight = Math.max(childHeight, lineHeight);
if (childLeft + childWidth + paddingRight > selfWidth) {
childLeft = paddingLeft;
childTop += mVerticalSpacing + lineHeight;
lineHeight = childHeight;
} else {
childLeft += childWidth + mHorizontalSpacing;
}
}
首先通过循环。遍历这个控件的所有子控件。同一时候调用子控件的measure()方法。这时measure方法的两个參数是控件能给这个子控件的最大宽高(我们都知道的,子控件再大。显示的大小也不能比父控件还大)。这里getChildMeasureSpec()方法的作用是用来计算一个合适子视图的尺寸大小(宽度或者高度),结合我们从子视图的LayoutParams所给出的MeasureSpec信息来获取最合适的结果。比方,假设这个View知道自己的大小尺寸(由于它本身的MeasureSpec的model为Exactly,)而且子视图的大小恰好跟父窗体一样大,父窗体必须用给定的大小去layout子视图
參数含义:spec 父窗体传递给子视图的大小和模式
padding 父窗体的边距,也就是xml中的android:padding
childDimension 子视图想要绘制的准确大小,但终于不一定绘制此值
当得到了每个子控件的大小以后。再要计算自己的宽高就简单了。
int wantedHeight = childTop + lineHeight + paddingBottom;
同理,在onLayout中的这一句
for (int i = 0, childCount = getChildCount(); i < childCount; ++i) {
View childView = getChildAt(i);
if (childView.getVisibility() == View.GONE) {
continue;
}
int childWidth = childView.getMeasuredWidth();
int childHeight = childView.getMeasuredHeight();
lineHeight = Math.max(childHeight, lineHeight);
if (childLeft + childWidth + paddingRight > myWidth) {
childLeft = paddingLeft;
childTop += mVerticalSpacing + lineHeight;
lineHeight = childHeight;
}
childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
childLeft += childWidth + mHorizontalSpacing;
}
首先通过循环遍历,控制每个item子控件的显示位置。假设当前行还能放得下一个item。就放到当前行,假设放不下就放到下一行的最左边。
终于,遍历完毕,也就相当于把自己的位置显示完毕了。
效果截图

Android流式布局实现的更多相关文章
- android -------- 流式布局,支持单选、多选等
最近开发中有流式标签这个功能,网上学了下,来分享一下 Android 流式布局,支持单选.多选等,适合用于产品标签等. 效果图: 用法: dependencies { compile 'com.hym ...
- android流式布局、待办事项应用、贝塞尔曲线、MVP+Rxjava+Retrofit、艺术图片应用等源码
Android精选源码 android模仿淘宝首页效果源码 一款艺术图片应用,采用T-MVVM打造 Android MVP + RxJava + Retrofit项目 android流式布局实现热门标 ...
- 含有过滤功能的android流式布局
FilterFlowLayout 含有过滤功能的流式布局, 參考FlowLayout 能够去除宽度不在范围(比例或真实值)内的子view 能够设置最大行数 能够加入组件间水平间距 能够加入行间距 系统 ...
- Android流式布局控件
1,自定义flowlayout代码 package com.hyang.administrator.studentproject.widget; import android.content.Cont ...
- Android 自动换行流式布局的RadioGroup
效果图 用法 使用FlowRadioGroup代替RadioGroup 代码 import android.content.Context; import android.util.Attribute ...
- Android 自定义View修炼-Android中常见的热门标签的流式布局的实现
一.概述:在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出哈) 类似的 ...
- Android控件进阶-自定义流式布局和热门标签控件
技术:Android+java 概述 在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧,类 ...
- 【Android - 自定义View】之自定义可滚动的流式布局
首先来介绍一下这个自定义View: (1)这个自定义View的名称叫做 FlowLayout ,继承自ViewGroup类: (2)在这个自定义View中,用户可以放入所有继承自View类的视图,这个 ...
- Android自己定义之流式布局
流式布局,优点就是父类布局能够自己主动的推断子孩子是不是须要换行,什么时候须要换行,能够做到网页版的标签的效果. 今天就是简单的做了自己定义的流式布局. 详细效果: 原理: 事实上非常easy,Mea ...
随机推荐
- 如何利用多核CPU来加速你的Linux命令 — awk, sed, bzip2, grep, wc等
http://blog.chinaunix.net/uid-20662820-id-4023733.html http://www.faqs.org/faqs/snmp-faq/part2/ http ...
- Qt新建线程的方法(四种办法,很详细,有截图)
看了不少Qt线程的东西,下面总结一下Qt新建一个线程的方法. 一.继承QThread 继承QThread,这应该是最常用的方法了.我们可以通过重写虚函数void QThread::run ()实现我们 ...
- VS2012中的全部预定义键盘快捷键列表
原文 http://www.elanblog.com/2013/05/14/vs2012-key-list/#sectionToggle7 Visual Studio 集成开发环境 (IDE) 包括若 ...
- egret-android-support-gradle版
从3.1.3开始,Egret已经实现了Gradle构建!所以下文你爱看不看! 迟钝的Egret从3.1.3版本才开始支持Gradle,而笔者早在1.6.x版本就已经支持了,说明什么?说明Egret在某 ...
- ubuntu 14.04 vnc use gnome(ubuntu14.04 gnome for vnc4server)
New 'jenkinsmaster.cc:3 (root)' desktop is jenkinsmaster.cc:3 Starting applications specified in /ro ...
- Mvc4.0 提取 Cookie 里的东西
/// <summary> /// 提取Cookie /// </summary> /// <returns></returns> public sta ...
- Linux_常用命令
文件搜索 -find -locate -grep 字符串搜索 -grep 过滤 -grep/find/xargs/ 编辑 -sed 待续....
- 安装Eclipse Html Editor
最近在eclipse中开发android项目,用到了jquery mobile框架,则会涉及到新建html文件,发现eclipse不自带新建html文件的插件,必须得新建一个其他形式的文件,譬如xml ...
- mysql函数操作(2)
<?php $dbh = new PDO('mysql:dbname=testdb;host=localhost', 'mysql_user', 'mysql_pwd'); $dbh->s ...
- Windows系统环境下一个Apache运行多个PHP版本
我个人机器上环境是基于Apache2.2运行的PHP5.2/4,如你想部署其他版本的PHP或在更多的版本之间切换,同理操作步骤是一致的. 依本人环境为例,机器上已经安装了PHP5.2版本, 所以首先重 ...