欲实现如下效果:

思路很简单就2步:

1、测量出ViewGroup的大小

2、找出子View的位置

若要实现动态添加标签view,就要实现ViewGroup的onMeasure()、onLayout()方法,这两个方法可由该ViewGroup的requestLayout()方法触发,

onMeasure是对ViewGroup的大小计算,onLayout是针对View(可以是子View也可以是本View)的位置设置

关于这几个方法的流程图如下:

/*** 流式标签(动态的,根据传入的数据动态添加标签)*/
public class CustomerFlowLayout extends ViewGroup {private List<String> mTags = new ArrayList<String>();public CustomerFlowLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public CustomerFlowLayout(Context context, AttributeSet attrs) {super(context, attrs);}public CustomerFlowLayout(Context context) {super(context);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int widthMode = MeasureSpec.getMode(widthMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);//当前ViewGroup的总高度int totalHeight= 0;//所有行中的最大宽度int maxLineWidth = 0;//当前行的最大高度int lineMaxHeight = 0;//当前行的总宽度int currentLineWidth = 0;//每个childView所占用的宽度int childViewWidthSpace = 0;//每个childView所占用的高度int childViewHeightSpace = 0;int count = getChildCount();MarginLayoutParams layoutParams;for(int i = 0; i < count; i++){View child = getChildAt(i);if(child.getVisibility() != View.GONE){//只有当这个View能够显示的时候才去测量//测量每个子View,以获取子View的宽和高
                measureChild(child, widthMeasureSpec, heightMeasureSpec);layoutParams = (MarginLayoutParams) child.getLayoutParams();childViewWidthSpace = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;childViewHeightSpace = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;if(currentLineWidth + childViewWidthSpace > widthSize){//表示如果当前行再加上现在这个子View,就会超出总的规定宽度,需要另起一行totalHeight += lineMaxHeight;if(maxLineWidth < currentLineWidth){//如果行的最长宽度发生了变化,更新保存的最长宽度maxLineWidth = currentLineWidth;}currentLineWidth = childViewWidthSpace;//另起一行后,需要重置当前行宽lineMaxHeight = childViewHeightSpace;}else{//表示当前行可以继续添加子元素currentLineWidth += childViewWidthSpace;if(lineMaxHeight < childViewHeightSpace){lineMaxHeight = childViewHeightSpace;}}}}setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : maxLineWidth, heightMode == MeasureSpec.EXACTLY ? heightSize : totalHeight);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {//当前是第几行int currentLine = 1;//存放每一行的最大高度List<Integer> lineMaxHeightList = new ArrayList<Integer>();//每个childView所占用的宽度int childViewWidthSpace = 0;//每个childView所占用的高度int childViewHeightSpace = 0;//当前行的最大高度int lineMaxHeight = 0;//当前行的总宽度int currentLineWidth = 0;int count = getChildCount();MarginLayoutParams layoutParams;for(int i = 0; i < count; i++){int cl= 0, ct = 0, cr = 0, cb = 0;View child = getChildAt(i);if(child.getVisibility() != View.GONE){//只有当这个View能够显示的时候才去测量
            layoutParams = (MarginLayoutParams) child.getLayoutParams();childViewWidthSpace = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;childViewHeightSpace = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;System.out.println("getWidth()---->"+getWidth());if(currentLineWidth + childViewWidthSpace > getWidth()){//表示如果当前行再加上现在这个子View,就会超出总的规定宽度,需要另起一行lineMaxHeightList.add(lineMaxHeight);//此时先将这一行的最大高度加入到集合中//新的一行,重置一些参数currentLine++;currentLineWidth = childViewWidthSpace;lineMaxHeight = childViewHeightSpace;cl = layoutParams.leftMargin;if(currentLine > 1){for(int j = 0; j < currentLine - 1; j++){ct += lineMaxHeightList.get(j);}ct += layoutParams.topMargin ;}else{ct = layoutParams.topMargin;}}else{//表示当前行可以继续添加子元素cl = currentLineWidth + layoutParams.leftMargin;if(currentLine > 1){for(int j = 0; j < currentLine - 1; j++){ct += lineMaxHeightList.get(j);}ct += layoutParams.topMargin;}else{ct = layoutParams.topMargin;}currentLineWidth += childViewWidthSpace;if(lineMaxHeight < childViewHeightSpace){lineMaxHeight = childViewHeightSpace;}}cr = cl + child.getMeasuredWidth();cb = ct + child.getMeasuredHeight();child.layout(cl, ct, cr, cb);}}}@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {return new MarginLayoutParams(getContext(), attrs);}public void setTags(List<String> tags){if(tags!= null){mTags.clear();mTags.addAll(tags);for(int i = 0; i < mTags.size(); i++){TextView tv = new TextView(getContext());MarginLayoutParams lp = new MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT);lp.setMargins(15, 15, 15, 15);
//                lp.width = MarginLayoutParams.WRAP_CONTENT;
//                lp.height = MarginLayoutParams.WRAP_CONTENT;
                tv.setLayoutParams(lp);tv.setBackgroundResource(R.drawable.tv_bg);/** setPadding一定要在setBackgroundResource后面使用才有效!!!* http://stackoverflow.com/questions/18327498/setting-padding-for-textview-not-working*/tv.setPadding(15, 15, 15, 15);tv.setTextColor(Color.WHITE);tv.setText(mTags.get(i));tv.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if(listener != null){listener.onClick(v);}}});addView(tv);}requestLayout();}}private OnTagItemClickListener listener;public interface OnTagItemClickListener{public void onClick(View v);}public void setOnTagItemClickListener(OnTagItemClickListener l){listener = l;}}

针对在Activity中的使用:

public class MainActivity extends Activity {private CustomerFlowLayout customerFlowLayout;List<String> tags = new ArrayList<String>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_dynamic_tagflowlayout);CustomerFlowLayout = (CustomerFlowLayout) findViewById(R.id.dynamic_tag);customerFlowLayout.setOnTagItemClickListener(new OnTagItemClickListener() {@Overridepublic void onClick(View v) {TextView tv = (TextView) v;Toast.makeText(MainActivity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show();}});initData();customerFlowLayout.setTags(tags);}private void initData() {tags.add("阳哥你好!");tags.add("Android开发");tags.add("新闻热点");tags.add("热水进宿舍啦!");tags.add("I love you");tags.add("成都妹子");tags.add("新余妹子");tags.add("仙女湖");tags.add("创新工厂");tags.add("孵化园");tags.add("神州100发射");tags.add("有毒疫苗");tags.add("顶你阳哥阳哥");tags.add("Hello World");tags.add("闲逛的蚂蚁");tags.add("闲逛的蚂蚁");tags.add("闲逛的蚂蚁");tags.add("闲逛的蚂蚁");tags.add("闲逛的蚂蚁");tags.add("闲逛的蚂蚁");}}

上述的ViewGroup中可以添加 对标签的处理(例如:点击、选中)

参考资料:

https://blog.csdn.net/shakespeare001/article/details/51089128

https://www.cnblogs.com/ldq2016/p/9035332.html

转载于:https://www.cnblogs.com/bimingcong/p/9947739.html

自定义View(四) ViewGroup 动态添加变长Tag标签 支持自动换行相关推荐

  1. 【Android 应用开发】自定义View 和 ViewGroup

    一. 自定义View介绍 自定义View时, 继承View基类, 并实现其中的一些方法. (1) ~ (2) 方法与构造相关 (3) ~ (5) 方法与组件大小位置相关 (6) ~ (9) 方法与触摸 ...

  2. 安卓自定义View(四)重叠View(灵感来自头像重叠)

    最近同事需要实现如下效果的一个功能,我闲来无事就试着实现了一下,以下是具体功能的实现步骤: 功能要求: 可以水平滚动 动态添加个数不定 可点击 点击后变为选中色 功能实现: 自定义View packa ...

  3. Android开发之RecyclerView动态添加item长按删除item源码

    我们先看下效果图: 效果还是很不错的. 实现思路: 设置recyclerview为GridLayoutManager布局,单行个数为4个 GridLayoutManager linearLayoutM ...

  4. 【Android】Android自定义View和ViewGroup知识点汇总

    一.View的绘制流程 onMeasure()->onDraw(). 二.ViewGroup的绘制流程 onMeasure()->onLayout()->onDraw()(一般不重写 ...

  5. 精通Android自定义View(四)自定义属性使用详解

    1.简述 对于自定义属性,遵循以下几步,就可以实现: 自定义一个CustomView(extends View )类 编写values/attrs.xml,在其中编写styleable和item等标签 ...

  6. Android自定义View(四)——仿Android5.0波纹效果

    项目源码比较简单,直接看帖的代码就可以了. 说实话,我是真没有去看RippleView的源码,只是从表面看到它的效果,所以产生了一点思路,所以功能很有局限性,而且用起来也比较复杂,大家且看且喷就好^_ ...

  7. android自定义游戏闯关图,Android自定义View(四) -- Canvas

    本文计划根据HenCoder系列文章进行学习,所以代码风格及博文素材可能会摘自其中. 1 范围裁切 范围裁切有两个方法: clipRect() 和 clipPath().裁切方法之后的绘制代码,都会被 ...

  8. android 自定义View ----- 类似黄油相机添加文字

    因为公司项目需求,要做一个类似于黄油相机那样添加文字的功能 可是网上到处找,资料特别少..就摸索着自己写吧... 图片这部分很简单...就是一个RelativeLayout里面先添加一个imageVi ...

  9. android开发自定义View(四)仿掌上英雄联盟能力值分析效果

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 原始图效果 模仿效果 PNG GIF 流程 绘制中心线,用于计算外层多边形各点的坐标 绘制最外层多边形 分析原型图算出每个多边形之间 ...

最新文章

  1. 这两天被木马程序搞得好烦
  2. Office 2007无法修复、卸载、重装
  3. CSS的inline、block与inline-block
  4. 《信息系统项目管理师软考辅导——3年真题详解与全真模拟》主要创新点、关注点...
  5. excel 两列数据怎么把组合的可能全部做出来?
  6. 2018年房价到底会不会涨!
  7. Theano 中文文档 0.9 - 5.4 CentOS 6安装说明
  8. 电脑桌面便签_电脑桌面便签软件哪个好
  9. [转]解决Sublime Text 2中文显示乱码问题
  10. “互联网+”大赛全市第三名软件杯全国第一名 - Cloud Lab商业策划书
  11. word中批量修改上角标、下角标
  12. JS 解决IE浏览器出现Automation 服务器不能创建对象
  13. 我坚持写公众号的初衷是什么?
  14. linux 不自动进入睡眠,linux 7 为何自动睡眠
  15. 软件开发模型-瀑布模型、V形模型、原型模型、增量模型、快速开发、敏捷模型
  16. pci配置基地址_PCI/PCIe基础——配置空间
  17. 判断字符串不超过20个字符_如何阻止超过140个字符的推文(如果确实需要)
  18. 程序员面试需要刷力扣算法题吗
  19. gpu虚拟化云服务器,gpu云服务器 虚拟化
  20. 京东wskey到底怎么抓?

热门文章

  1. oracle asm参数优化,关于ASM参数文件的问题
  2. 基于高光谱成像的苹果病害无损检测方法
  3. 冬小麦病虫害的高光谱识别方法研究
  4. 解读cartographer/common/port.h--Cartographer(一)
  5. 跨区域报考计算机考试可以吗,考生注意!2020年医师资格机考跨题型不可以回看(附上机操作系统)...
  6. 求有向图中两点最短距离java_Java 迪杰斯特拉算法实现查找最短距离
  7. gulp安装指定版本_对比webpack,你更应该先掌握gulp【10分钟教你彻底掌握gulp】
  8. 在大项目中,实施顾问主要负责什么具体工作?
  9. 某大型银行深化系统技术方案之七:核心层之流程控制引擎
  10. Eclipse用法和技巧十一:分栏显示