前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自定义FlowLayout,android flowLayout实现

自定义FlowLayout,android flowLayout实现

作者头像
再见孙悟空_
发布2023-02-10 19:50:36
2830
发布2023-02-10 19:50:36
举报

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

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

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

方法还是重写onMeasure和onLayout

话不多说  ,代码贴上

一.自定义view

代码语言:javascript
复制
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布局中加上这个

代码语言:javascript
复制
  <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" />

三.初始化数据部分

代码语言:javascript
复制
	@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就是你要填充的数据集合

基本核心的东西就上面这些 ,最上面的图是我的项目里面最后实现的效果图。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-08-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档