写在前面
本文原创,转载请以链接形式注明地址:http://kymjs.com/code/2015/06/06/01
新项目用到了一种全新布局————Android标签流式布局的功能,正好一直说给大家讲自定义控件的实现,今天就为大家讲一种android流式布局的实现。
在日常的app使用中,我们会在android 的app中看见热门标签等自动换行的流式布局,今天,我们就来看看如何自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出)
这个控件并不是我实现的,代码是从网上搜流式布局找到的。我只是为大家讲解一下实现过程以及原理。
先看代码
public classFlowLayoutextendsViewGroup{
private float mVerticalSpacing; //每个item纵向间距
private float mHorizontalSpacing; //每个item横向间距
publicFlowLayout(Contextcontext){
super(context);
}
publicFlowLayout(Contextcontext,AttributeSetattrs){
super(context, attrs);
}
publicvoidsetHorizontalSpacing(floatpixelSize){
mHorizontalSpacing = pixelSize;
}
publicvoidsetVerticalSpacing(floatpixelSize){
mVerticalSpacing = pixelSize;
}
@Override
protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
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
protectedvoidonLayout(booleanchanged,intl,intt,intr,intb){
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流式布局的实现主要涉及对ViewGroup的`onMeasure()`和`onLayout()`方法的重写。通过这种方式,我们可以创建出高度自适应且布局灵活的应用界面,尤其适用于展示大量未知数量的元素,如标签、卡片等。`...
本篇文章将深入探讨如何使用自定义的流式布局实现这一功能。 首先,我们理解一下什么是流式布局。流式布局是一种灵活的布局方式,它允许子视图根据可用空间自动流动到下一行,类似于文本的排版。与GridView的固定...
本文将深入探讨如何使用流式布局(FlowLayout)实现热门标签的效果。流式布局是一种允许子视图在一行内填充空间,当一行填满时自动换行的布局方式,非常适合用于展示标签云或类似效果。 首先,我们要理解“热门标签...
在Android应用开发中,流式布局(FlowLayout)是一种常见的布局方式,它允许子视图按照从左到右、从上到下的顺序排列,当一行填满后会自动换行。这种布局非常适合用来展示类似历史搜索记录这样的数据,因为它可以...
本教程将深入探讨如何在Android中简单地实现一个流式布局。 首先,我们需要创建一个新的ViewGroup类,继承自LinearLayout,因为LinearLayout已经具有了基本的布局管理能力。我们将这个新的类命名为FlowLayout。在...
在我们开发过程中,我们有的时候会碰到这么一种需求,就是需要单选,但是呢?得多行显示要选的内容item,常规做法使用...这就有点郁闷了,没关系,今天我们来提供一种新的实现方式,那就是流式布局来实现类似功能。
在"Android-Android流式布局FlowLayout实现关键字标签"这个主题中,我们将深入探讨如何在Android项目中创建并使用FlowLayout。首先,我们需要了解FlowLayout的基本原理: 1. **FlowLayout类的创建**: 自定义...
本篇文章将深入探讨如何实现一个自定义的“流式布局”(Flow Layout),这是一种能够自动调整子视图(child views)排列方式,根据屏幕尺寸变化而保持良好的视觉效果的布局方式。 一、理解流式布局 流式布局是一种...
综上所述,流式布局在Android开发中提供了灵活的布局方案,通过自定义实现和功能扩展,可以更好地满足各种复杂的界面需求。在实际项目中,我们可以根据应用的特性和用户需求,定制化我们的流式布局,提高应用的可用...
实现Android的流式布局,你需要创建一个自定义ViewGroup类,继承自ViewGroup。关键在于重写onMeasure()和onLayout()方法。在onMeasure()中,你需要测量所有子视图的尺寸,并确定总宽度和高度。在onLayout()中,你...
流式布局, 这个概念在移动端或者前端开发中很常见,特别是在多标签的展示中, 往往起到了关键的作用。公司最近要做一个标签管理,标签可删除,可添加,长按可以拖动。网上很多流式布局的列子,大部分都不能满足需求...
下面我们将深入探讨Android流式布局的原理、使用方法以及如何实现它。 一、流式布局简介 流式布局不同于常见的线性布局(LinearLayout)、相对布局(RelativeLayout)或帧布局(FrameLayout),它允许子视图在一行...
Android流式布局,支持点击、单选、多选等,适合用于产品标签等,用法采用Adapter模式,和ListView、GridView用法一样!2016/6/26号新添加初始化标签功能,使用非常简单,只要你的Adapter实现OnInitSelectedPosition...
在"Android 流式布局效果.zip"这个资源包中,重点展示了如何在Android应用中实现类似标签云的动态效果,这种效果通常用于展示多样化且数量较多的标签,用户可以轻松滚动浏览和交互。 **流式布局的优势:** 1. 自动...
在给定的实例"Android流式布局实例"中,我们可以深入探讨以下几个关键知识点: 1. **自定义Viewpager**: 自定义ViewPager是Android原生ViewPager的扩展,它允许开发者根据特定需求调整其行为和功能。在本实例中,...
以下将详细介绍如何用线性布局实现流式布局。 1. **线性布局基础** 线性布局(LinearLayout)是Android中最基础的布局之一,它可以将子视图按照垂直或水平方向排列。默认情况下,子视图会按照从左到右、从上到下的...
在提供的“安卓UI布局相关-android流式布局子项的添加和移除等功能.rar”文件中,开发者可能已经实现了自定义FlowLayout的功能,包括添加和移除子项的操作。这些功能对于创建灵活、响应式的用户界面非常有用。 添加...
在Android开发中,自定义...总结,自定义Android流式布局涉及到了ViewGroup的测量、布局过程,以及一些优化和扩展的策略。理解并掌握这些知识点,可以帮助开发者实现更多定制化的布局效果,提升应用的用户体验。
标题提到的“Android流式布局FlowLayout”是一种非标准但非常实用的布局方式,尤其在处理多个元素排列时,它能提供灵活且直观的解决方案。让我们深入了解一下FlowLayout及其在Android开发中的应用。 FlowLayout类似...
总的来说,Android流式布局和热门标签是移动应用中常见的设计元素,它们能够有效地组织和展示信息,提高用户界面的可读性和交互性。通过理解流式布局的工作原理和实现方式,以及如何设计和实现热门标签,开发者可以...