自定义FlowLayout,android flowLayout实现

我想大家在开发过程中都碰到过这样的需求,类似标签展示,要展示如上图效果,这里面的数据不确定每项字数,有的非常长,有的很短,数据动态填充。

这种情况用listView和gridView展示效果都没有上图的效果。

这时我们其实是要自己写一个控件来填充上图的数据,也就是我们今天要说的自定义view,流式布局。

方法还是重写onMeasure和onLayout

话不多说  ,代码贴上

一.自定义view

package com.jky.mobilebzt.view;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

public class XCFlowLayout extends ViewGroup {
	// 存储所有子View
	private List<List<View>> mAllChildViews = new ArrayList<List<View>>();
	// 每一行的高度
	private List<Integer> mLineHeight = new ArrayList<Integer>();

	public XCFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

	public XCFlowLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public XCFlowLayout(Context context) {
		this(context, null);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		// 父控件传进来的宽度和高度以及对应的测量模式
		int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
		int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
		int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
		int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

		// 如果当前ViewGroup的宽高为wrap_content的情况
		int width = 0; // 自己测量的宽度
		int height = 0; // 自己测量的高度

		int lineWidth = 0;// 每一行的宽度
		int lineHeight = 0; // 每一行的高度

		int childCount = getChildCount();// 获取子view的个数
		for (int i = 0; i < childCount; i++) {
			View child = getChildAt(i);
			// 测量子View的宽和高
			measureChild(child, widthMeasureSpec, heightMeasureSpec);
			// 得到LayoutParams
			MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
			// 得到子View占据的宽度
			int childWidth = child.getMeasuredWidth() + lp.leftMargin
					+ lp.rightMargin;
			// 得到子View占据的高度
			int childHeight = child.getMeasuredHeight() + lp.topMargin
					+ lp.bottomMargin;
			if (lineWidth + childWidth > sizeWidth) {// 需要进行换行
				width = Math.max(width, lineWidth); // 得到最大宽度
				lineWidth = childWidth; // 重置lineWidth
				height += lineHeight; // 得到高度
				lineHeight = childHeight;// 重置LineHeight
			} else {// 不需要进行换行
				lineWidth += childWidth;// 叠加行宽
				lineHeight = Math.max(lineHeight, childHeight);
			}

			if (i == childCount - 1) {// 处理最后一个子View的情况
				width = Math.max(width, lineWidth);
				height += lineHeight;
			}
		}

		// wrapcontent
		setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth
				: width, modeHeight == MeasureSpec.EXACTLY ? sizeHeight
				: height);

//		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// TODO Auto-generated method stub
		mAllChildViews.clear();
		mLineHeight.clear();

		int width = getWidth();// 获取当前ViewGroup宽度
		int lineWidth = 0;
		int lineHeight = 0;

		List<View> lineViews = new ArrayList<View>();// 记录当前行的View
		int childCount = getChildCount();
		for (int i = 0; i < childCount; i++) {
			View child = getChildAt(i);
			MarginLayoutParams lp = (MarginLayoutParams) child
					.getLayoutParams();
			int childWidth = child.getMeasuredWidth();
			int childHeight = child.getMeasuredHeight();

			// 需要换行
			if (lineWidth + childWidth + lp.leftMargin + lp.rightMargin > width) {
				mLineHeight.add(lineHeight); // 记录lineHeight
				mAllChildViews.add(lineViews); // 记录当前行的Views
				// 重置 行的宽高
				lineWidth = 0;
				lineHeight = childHeight + lp.topMargin + lp.bottomMargin;
				// 重置当前行的View集合;
				lineViews = new ArrayList<View>();
			}

			lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
			lineHeight = Math.max(lineHeight, childHeight + lp.topMargin
					+ lp.bottomMargin);
			lineViews.add(child);
		}
		// 处理最后一行
		mLineHeight.add(lineHeight);
		mAllChildViews.add(lineViews);

		// 设置子View的位置
		int left = 0;
		int top = 0;
		// 获取行数
		int lineCount = mAllChildViews.size();
		for (int i = 0; i < lineCount; i++) {
			// 当前行的views和高度
			lineViews = mAllChildViews.get(i);
			lineHeight = mLineHeight.get(i);
			for (int j = 0; j < lineViews.size(); j++) {
				View child = lineViews.get(j);
				// 判断是否显示
				if (child.getVisibility() == View.GONE) {
					continue;
				}
				MarginLayoutParams lp = (MarginLayoutParams) child
						.getLayoutParams();
				int cLeft = left + lp.leftMargin;
				int cTop = top + lp.topMargin;
				int cRight = cLeft + child.getMeasuredWidth();
				int cBottom = cTop + child.getMeasuredHeight();
				// 进行子View进行布局
				child.layout(cLeft, cTop, cRight, cBottom);
				left += child.getMeasuredWidth() + lp.leftMargin
						+ lp.rightMargin;
			}
			left = 0;

			top += lineHeight;
		}
	}

	/**
	 * 与当前ViewGroup对应的LayoutParams
	 */
	@Override
	public LayoutParams generateLayoutParams(AttributeSet attrs) {
		return new MarginLayoutParams(getContext(), attrs);
	}
}

二.xml部分

xml布局中加上这个

  <com.jky.mobilebzt.view.XCFlowLayout
                android:id="@+id/xcf_hot_words"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/margin_lsmall"
                android:layout_marginBottom="@dimen/margin_normal"
                android:layout_marginRight="@dimen/margin_normal" />

三.初始化数据部分

	@SuppressLint("NewApi")
	private void initHotWordViews() {
		MarginLayoutParams lp = new MarginLayoutParams(
				LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
		lp.leftMargin = 20;
		lp.rightMargin = 20;
		lp.topMargin = 8;
		lp.bottomMargin = 8;
		for (int i = 0; i < hotWords.size(); i++) {
			final String hotWord = hotWords.get(i);
			TextView view = new TextView(this);
			view.setGravity(Gravity.CENTER);
			view.setText(hotWords.get(i));
			view.setTextColor(Color.BLACK);
			view.setBackground(getResources().getDrawable(R.drawable.hot_word_selector));
			mFlowLayout.addView(view, lp);
			view.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
				
				}
			});
		}
	}

hotWords就是你要填充的数据集合
 

基本核心的东西就上面这些 ,最上面的图是我的项目里面最后实现的效果图。如果还有其他问题欢迎加入我们的qq群:

开发一群:454430053开发二群:537532956

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

再见孙悟空_

你的鼓励将是我最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值