查看我的所有开源项目【开源实验室】

欢迎增加我的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;
}
}
}

从控件创建过程说起

  1. 当这个流式布局在被载入如内存并显示在屏幕上这一过程中。首先会调用view.measure(w,h)这种方法,表示測量view的宽度与高度。当中參数w与h分别表示这个控件的父控件的宽高。
  2. 在view.measure()方法的调用过程中又会调用view本身的一个回调方法,onMeasure(),这个是view自身的一个回调方法。用于让开发人员在自己定义View的时候又一次计算自身的大小。通常会在这种方法中循环遍历,计算出这个控件的所有子孙控件的宽高。
  3. 在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流式布局实现的更多相关文章

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

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

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

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

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

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

  4. Android流式布局控件

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

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

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

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

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

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

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

  8. 【Android - 自定义View】之自定义可滚动的流式布局

    首先来介绍一下这个自定义View: (1)这个自定义View的名称叫做 FlowLayout ,继承自ViewGroup类: (2)在这个自定义View中,用户可以放入所有继承自View类的视图,这个 ...

  9. Android自己定义之流式布局

    流式布局,优点就是父类布局能够自己主动的推断子孩子是不是须要换行,什么时候须要换行,能够做到网页版的标签的效果. 今天就是简单的做了自己定义的流式布局. 详细效果: 原理: 事实上非常easy,Mea ...

随机推荐

  1. ubuntu gnome vnc

    1,安装登陆管理器 --apt-get install gdm (还可以为kdm/xdm) lightdm,display manager

  2. rootvg 镜像

    具体操作步骤如下 : a)        查看一下当前可用的硬盘: # lspv hdisk0          0002d74f0e69d97a                    rootvg ...

  3. 关于 unity3d securityexception no valid crossdomain policy available 的错误解决方法

    错误大概就是这样的,事实上我一直没有注意,好像是我转平台到webplayer的关系,就无法访问自己的服务器上面的东东了,现在怎么做呢? 在自己的服务器根目录(哪个是根目录不懂,可以去投胎了哈),创建一 ...

  4. wxpython 中的所有控件及高级应用

    转自http://xoomer.virgilio.it/infinity77/Phoenix/lib.agw.html,,,哈哈终于找到了这块的内容,书上基本没有讲解 This is the Adva ...

  5. C# DataTable转实体 通用方法【转】

    public static T GetEntity<T>(DataTable table) where T : new()    {        T entity = new T();  ...

  6. Android不规则瀑布流照片墙的实现+LruCache算法

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZnJhbmNpc3NoaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  7. hdu4740【杭州网赛、模拟、有点搜索?】

    当时看了这题就感觉so easy...  本来不想写的,后来感觉是不是可以练一下搜索水平.. 比赛时有人过了就没写.       比赛完了写一下. 实现还不是那么顺利,  囧 本来自己以为这题能练下搜 ...

  8. jquery Ztree v3.5 实例2 自定义显示在节点前的图片

    显示效果如下: 代码如下: <html> <head><title></title></head> <script type=&quo ...

  9. C#.NET学习笔记1---C#.NET简介

    C#.NET学习笔记1---C#.NET简介 技术qq交流群:JavaDream:251572072  教程下载,在线交流:创梦IT社区:www.credream.com -------------- ...

  10. IOS 获取手机各种信息

    /手机序列号      NSString* identifierNumber = [[UIDevice currentDevice] uniqueIdentifier];     NSLog(@&qu ...