android流式布局控件

原创 2016年08月29日 16:07:17

另外再说一个控件,先看效果图:




使用代码如下:


private void init() {
		FlowLayout flow = (FlowLayout) findViewById(R.id.flow);
		for(String s : data){
			TextView tv = new TextView(this);
			tv.setText(s);
			
			int padding = dip2Px(5);
			tv.setPadding(padding, padding, padding, padding);
			tv.setGravity(Gravity.CENTER);
			tv.setTextColor(Color.WHITE);
			
			GradientDrawable bg = new GradientDrawable();
			bg.setCornerRadius(dip2Px(6));
			Random random = new Random();
			int alpha = 255;
			int red = random.nextInt(190)+30;
			int green = random.nextInt(190)+30;
			int blue = random.nextInt(190)+30;
			int argb = Color.argb(alpha, red, green, blue);
			bg.setColor(argb);
			
			tv.setClickable(true);
			tv.setBackgroundDrawable(bg);
			int dip = dip2Px(5);
			flow.setSpace(dip, dip);
			
			flow.addView(tv);
		}
	}

很简单,FlowLayout继承ViewGroup,用addView将View添加进去就行,有兴趣的童鞋可以写一个Adapter方便使用,老规矩,本人一向喜欢直入主题,看源码实现:


public FlowLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public FlowLayout(Context context) {
		super(context);
	}

可见构造方法没有改变。


@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// 清空记录
		mLines.clear();
		mCurrentLine = null;

		// 获得layout的宽度
		int widthSize = MeasureSpec.getSize(widthMeasureSpec);
		int childMaxWidth = widthSize - getPaddingLeft() - getPaddingRight();
		// 子控件个数
		int count = getChildCount();
		// 测量孩子
		for (int i = 0; i < count; i++) {
			// 具体孩子
			View child = getChildAt(i);
			// 判断是否显示
			if (child.getVisibility() == View.GONE) {
				continue;
			}
			// 测量每一个孩子
			measureChild(child, widthMeasureSpec, heightMeasureSpec);

			// 记录孩子到行中
			if (mCurrentLine == null) {
				// 新建一行
				mCurrentLine = new Line(childMaxWidth, mHorizontalSpace);
				// 将这一行记录到list
				mLines.add(mCurrentLine);
			}

			if (mCurrentLine.canAdd(child)) {
				// 可以添加
				mCurrentLine.addView(child);
			} else {
				// 不可以添加
				// 新建一行
				mCurrentLine = new Line(childMaxWidth, mHorizontalSpace);
				// 将这一行记录到list
				mLines.add(mCurrentLine);
				// 将child加到line
				mCurrentLine.addView(child);
			}
		}
		
		// 行的高度的累加
		int heightSize = getPaddingTop() + getPaddingBottom();
		for (int i = 0; i < mLines.size(); i++) {
			Line line = mLines.get(i);
			heightSize += line.mHeight;

			if (i != 0) {
				// 垂直的间隙
				heightSize += mVerticalSpace;
			}
		}
		// setMeasuredDimension:设置自己宽度和高度
		setMeasuredDimension(widthSize, heightSize);
	}

自定义View中的三方法之一,onMeasure中先是计算出了自身的宽度,再通知子View测量,这是为了得到子View的具体大小,在通过行容器判断能否添加,如果不能新建一行,最后计算出自身的宽高设定。


@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// 获取上边距
		int top = getPaddingTop();
		// 遍历行
		for (int i = 0; i < mLines.size(); i++) {
			Line line = mLines.get(i);
			// 让行布局
			line.layout(getPaddingLeft(), top);
			// 高度计算
			top += line.mHeight;
			// 加上间隙
			if (i != mLines.size() - 1) {
				top += mVerticalSpace;
			}
		}
	}

自定义View中的三方法之一,onLayout用于计算View放置的位置,left值交由Line内部计算,这里主要计算每个Line的Top。


Line是FlowLayout内部的封装类,用来记录描述 layout中的行的信息,它只有一个构造方法。


// 构造
		public Line(int maxWidth, int space) {
			this.mMaxWidth = maxWidth;
			this.mSpace = space;
		}

mMaxWidth代表最大宽度,mSpace代表间隙。


/** 布局 */
		public void layout(int pLeft, int pTop) {
			// 多余的宽度
			int extraWidth = mMaxWidth - mCurrentWidth;
			// 获得平均值
			int avgWidth = (int) (extraWidth * 1f / mViews.size() + .5f);

			// 给View布局
			for (int i = 0; i < mViews.size(); i++) {
				View view = mViews.get(i);
				// 测量宽
				int width = view.getMeasuredWidth();
				// 测量高
				int height = view.getMeasuredHeight();
				// 平均值大于0
				if (avgWidth > 0) {
					// 指定孩子具体的大小
					view.measure(MeasureSpec.makeMeasureSpec(width + avgWidth,
							MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
							height, MeasureSpec.EXACTLY));
					// 重新获取宽高
					width = view.getMeasuredWidth();
					height = view.getMeasuredHeight();
				}
				// 多余的高度
				int extraHeight = mHeight - height;

				// 指定左边距
				int l = pLeft;
				// 指定上边距
				int t = (int) (pTop + extraHeight / 2f + .5f);
				// 右边据
				int r = l + width;
				// 下边据
				int b = t + height;

				// 设置控件大小
				view.layout(l, t, r, b);

				// 左值计算
				pLeft += width + mSpace;
			}
		}

这里的主要方法就是这个onLayout,计算行内View所要安置的位置,具体的都写了注释,不多讲。


最后同样附上Demo以供参考。

版权声明:本文为博主原创文章,未经博主允许不得转载。

Android自定义控件--流式布局(FlowLayout)

效果图: /* *首先需要先自定义一个类然后继承ViewGroup *然后看看onMeasure()方法的实现 *然后看看onLayout()方法的实现 * */ ...

Android流式标签布局,自定义标签控件tagView

我们在一些项目中会用到自定义流式布局,我个人觉得流式布局将呆板的布局错综排列,来提升用户体验度.(还可以不辜负美工妹子们的期望,人家毕竟也辛辛苦苦设计半天)。今天终于有时间来做做了。写的不好,很多地方...

Android自定义控件 - 标签流式布局

重写onMeasure计算childView宽度,如果当前ChildView放不下当前行,那么当前行剩余的空间由当前行其它控件平分,当前childView放入下一行,如果childView大于父Vie...

android 自定义控件实现流式布局

android 自定义控件实现流式布局

Android自定义控件之流式布局

脑筋急转: 在一个房间里,有油灯 ,暖炉及壁炉。现在,想要用一根火柴将三个器具点燃,请问首先应该点燃哪一个? 请查看文章最后有有解析...

分享一个比较好用的流式布局的label控件

Android流式布局,可配置是否将每一行的空白区域平均分配给子控件。 增加了将每一行的空白区域平均分配给子控件。 demo中分别演示了在xml使用方式和在java代码中动态添加 先介绍一下最...
  • nnmmbb
  • nnmmbb
  • 2016年01月14日 17:12
  • 918

自定义控件实践——流式布局

在本文中,我们将实现一个自定义控件,类似水平方向的 LinearLayout,区别是:当水平方向上空间不足时,子 View 自动从下一行开始放置。这种控件有个统称:流式布局(FlowLayout)。...
  • zhaizu
  • zhaizu
  • 2016年09月05日 19:40
  • 477

自定义ViewGroup控件(一)----->流式布局进阶(一)

自定义ViewGroup控件(一)----->流式布局进阶(一)

AutoFlowLayout:多功能流式布局与网格布局控件

近期工作需要用到流式布局,网上也有很多关于这方面的资料。发现流式布局与网格布局的自定义很有意思,是学习自定义控件的一个很好的方式,所以就撸了个几百行代码的控件,既实用又具有学习价值。 一、AutoFl...
  • LRH0211
  • LRH0211
  • 2017年08月09日 09:23
  • 287

android自定义流式布局源码

  • 2015年05月05日 20:26
  • 1.37MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android流式布局控件
举报原因:
原因补充:

(最多只允许输入30个字)