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

欢迎增加我的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. H面试程序(29):求最大递增数

    要求:求最大递增数 如:1231123451 输出12345 #include<stdio.h> #include<assert.h> void find(char *s) { ...

  2. ecshop后台添加菜单项,权限问题

    ecshop后台自定义菜单涉及到几个重要的权限控制的文件,先做如下总结: 后台添加菜单项,并设置权限的步骤.:(以在系统模块添加申请友链菜单为例)commn.php       : \language ...

  3. Python导入模块的三种形式

    Python导入模块的3中方式: 1.import module_name 这样在程序里就可以通过module_name.metnod_name()的方式访问模块里的函数了 Example: > ...

  4. poj3507---去掉最小值和最大值

    #include <stdio.h> #include <stdlib.h> int main() { ) { ,max=,min=,t; ; i<; i++) { sc ...

  5. Cannot retrieve metalink for repository: epel.

    Error: Cannot retrieve metalink for repository: epel. Please verify its path and                     ...

  6. Android系统移植与调试之------->如何修改Android设备的开机第一阶段Logo

    1.切换到~/mx0831-0525/device/other/TBDG1073/res_pack目录下 2.更换bootup和poweron文件 找一张bmp16位的图片去除后缀名将这两张都替换,转 ...

  7. Oracle Bills of Material and Engineering Application Program Interface (APIs)

    In this Document Goal   Solution   1. Sample Notes for BOM APIs   2. Datatypes used in these APIs   ...

  8. MessageQueue

    MessageQueue myQueue = new MessageQueue(".\\private$\\myQueue"); try { Message myMessage = ...

  9. struts2 模型驱动的action赋值优先顺序

    struts2 模型驱动的action赋值优先顺序: 1.优先设置model的属性. 2.如果model属性中没有对应的成员变量,则向上冒泡,寻找action中的属性进行set. 如果action中的 ...

  10. javascript高级程序设计一(80-116)

    81.函数内部属性:arguments.arguments.callee.this. window.color = "red"; var o={color:"blue&q ...