自定义FlowLayout,android flowLayout实现

2023-11-22 17:48

本文主要是介绍自定义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 {// 存储所有子Viewprivate 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);}@Overrideprotected 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);// 得到LayoutParamsMarginLayoutParams 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; // 重置lineWidthheight += lineHeight; // 得到高度lineHeight = childHeight;// 重置LineHeight} else {// 不需要进行换行lineWidth += childWidth;// 叠加行宽lineHeight = Math.max(lineHeight, childHeight);}if (i == childCount - 1) {// 处理最后一个子View的情况width = Math.max(width, lineWidth);height += lineHeight;}}// wrapcontentsetMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth: width, modeHeight == MeasureSpec.EXACTLY ? sizeHeight: height);//		super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stubmAllChildViews.clear();mLineHeight.clear();int width = getWidth();// 获取当前ViewGroup宽度int lineWidth = 0;int lineHeight = 0;List<View> lineViews = new ArrayList<View>();// 记录当前行的Viewint 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); // 记录lineHeightmAllChildViews.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*/@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {return new MarginLayoutParams(getContext(), attrs);}
}

二.xml部分

xml布局中加上这个

  <com.jky.mobilebzt.view.XCFlowLayoutandroid: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() {@Overridepublic void onClick(View v) {}});}}

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

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

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

这篇关于自定义FlowLayout,android flowLayout实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/411849

相关文章

Java实现MD5加密的四种方式

《Java实现MD5加密的四种方式》MD5是一种广泛使用的哈希算法,其输出结果是一个128位的二进制数,通常以32位十六进制数的形式表示,MD5的底层实现涉及多个复杂的步骤和算法,本文给大家介绍了Ja... 目录MD5介绍Java 中实现 MD5 加密方式方法一:使用 MessageDigest方法二:使用

mysql删除无用用户的方法实现

《mysql删除无用用户的方法实现》本文主要介绍了mysql删除无用用户的方法实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 1、删除不用的账户(1) 查看当前已存在账户mysql> select user,host,pa

Nginx配置location+rewrite实现隐性域名配置

《Nginx配置location+rewrite实现隐性域名配置》本文主要介绍了Nginx配置location+rewrite实现隐性域名配置,包括基于根目录、条件和反向代理+rewrite配置的隐性... 目录1、配置基于根目录的隐性域名(就是nginx反向代理)2、配置基于条件的隐性域名2.1、基于条件

Linux配置IP地址的三种实现方式

《Linux配置IP地址的三种实现方式》:本文主要介绍Linux配置IP地址的三种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录环境RedHat9第一种安装 直接配置网卡文件第二种方式 nmcli(Networkmanager command-line

Java实现将Markdown转换为纯文本

《Java实现将Markdown转换为纯文本》这篇文章主要为大家详细介绍了两种在Java中实现Markdown转纯文本的主流方法,文中的示例代码讲解详细,大家可以根据需求选择适合的方案... 目录方法一:使用正则表达式(轻量级方案)方法二:使用 Flexmark-Java 库(专业方案)1. 添加依赖(Ma

使用EasyExcel实现简单的Excel表格解析操作

《使用EasyExcel实现简单的Excel表格解析操作》:本文主要介绍如何使用EasyExcel完成简单的表格解析操作,同时实现了大量数据情况下数据的分次批量入库,并记录每条数据入库的状态,感兴... 目录前言固定模板及表数据格式的解析实现Excel模板内容对应的实体类实现AnalysisEventLis

Mybatis从3.4.0版本到3.5.7版本的迭代方法实现

《Mybatis从3.4.0版本到3.5.7版本的迭代方法实现》本文主要介绍了Mybatis从3.4.0版本到3.5.7版本的迭代方法实现,包括主要的功能增强、不兼容的更改和修复的错误,具有一定的参考... 目录一、3.4.01、主要的功能增强2、selectCursor example3、不兼容的更改二、

如何使用C#串口通讯实现数据的发送和接收

《如何使用C#串口通讯实现数据的发送和接收》本文详细介绍了如何使用C#实现基于串口通讯的数据发送和接收,通过SerialPort类,我们可以轻松实现串口通讯,并结合事件机制实现数据的传递和处理,感兴趣... 目录1. 概述2. 关键技术点2.1 SerialPort类2.2 异步接收数据2.3 数据解析2.

mybatis-plus 实现查询表名动态修改的示例代码

《mybatis-plus实现查询表名动态修改的示例代码》通过MyBatis-Plus实现表名的动态替换,根据配置或入参选择不同的表,本文主要介绍了mybatis-plus实现查询表名动态修改的示... 目录实现数据库初始化依赖包配置读取类设置 myBATis-plus 插件测试通过 mybatis-plu

Qt把文件夹从A移动到B的实现示例

《Qt把文件夹从A移动到B的实现示例》本文主要介绍了Qt把文件夹从A移动到B的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录如何移动一个文件? 如何移动文件夹(包含里面的全部内容):如何删除文件夹:QT 文件复制,移动(