Android自定义ViewGroup实现标签浮动效果

前面在学习鸿洋大神的一些自定义的View文章,看到了自定义ViewGroup实现浮动标签,初步看了下他的思路以及结合自己的思路完成了自己的浮动标签的自定义ViewGroup。目前实现的可以动态添加标签、可点击。效果图如下:

1、思路
 首先在onMeasure方法中测量ViewGroup的宽和高,重点是处理当我们自定义的ViewGroup设置为wrap_content的情况下,如何去测量其大小的问题。当我们自定义的ViewGroup设置为wrap_content时,我们需要让子View先去测量自己,当子View测量完后,再通过子View的getMeasuredWidth和getMeasureHeight方法获得其子View的宽和高。每次在测量一个子View之前,都需要判断如果加入该子View,当前行是否能够容纳下该子View,如果不能,则需要新开一行,并记录下当前行的最大高度。
 在onLayout方法中,核心人物是给每个子View摆放位置,也就是为该ViewGroup中每个子View找到盒子模型上面的两个点也就是左上角和右下角,即点(l,t)和点(r,b),确定了两个点,子View的位置也就确定了。

2、实现
 基本思路有了就可以尝试实现了,代码如下:
 自定义的ViewGroup:

/** * 流式标签(动态的,根据传入的数据动态添加标签) */ public class DynamicTagFlowLayout extends ViewGroup { private List<String> mTags = new ArrayList<String>(); public DynamicTagFlowLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public DynamicTagFlowLayout(Context context, AttributeSet attrs) { super(context, attrs); } public DynamicTagFlowLayout(Context context) { super(context); } @Override protected 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); } @Override protected 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); } } } @Override public 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() { @Override public 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; } }

MainActivity:

public class MainActivity extends Activity { private DynamicTagFlowLayout dynamicTagFlowLayout; List<String> tags = new ArrayList<String>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dynamic_tagflowlayout); dynamicTagFlowLayout = (DynamicTagFlowLayout) findViewById(R.id.dynamic_tag); dynamicTagFlowLayout.setOnTagItemClickListener(new OnTagItemClickListener() { @Override public void onClick(View v) { TextView tv = (TextView) v; Toast.makeText(MainActivity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show(); } }); initData(); dynamicTagFlowLayout.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("闲逛的蚂蚁"); } }

源码下载:Android流式标签可动态添加FlowLayout

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-11-10 05:38:31

Android自定义ViewGroup实现标签浮动效果的相关文章

Android自定义ViewGroup实现标签浮动效果_Android

前面在学习鸿洋大神的一些自定义的View文章,看到了自定义ViewGroup实现浮动标签,初步看了下他的思路以及结合自己的思路完成了自己的浮动标签的自定义ViewGroup.目前实现的可以动态添加标签.可点击.效果图如下: 1.思路  首先在onMeasure方法中测量ViewGroup的宽和高,重点是处理当我们自定义的ViewGroup设置为wrap_content的情况下,如何去测量其大小的问题.当我们自定义的ViewGroup设置为wrap_content时,我们需要让子View先去测量自

Android自定义ViewGroup实现标签流容器FlowLayout_Android

本篇文章讲的是Android 自定义ViewGroup之实现标签流式布局-FlowLayout,开发中我们会经常需要实现类似于热门标签等自动换行的流式布局的功能,网上也有很多这样的FlowLayout,但不影响我对其的学习.和往常一样,主要还是想总结一下自定义ViewGroup的开发过程以及一些需要注意的地方. 按照惯例,我们先来看看效果图 一.写代码之前,有几个是问题是我们先要弄清楚的: 1.什么是ViewGroup:从名字上来看,它可以被翻译为控件组,言外之意是ViewGroup内部包含了许

Android自定义ViewGroup实现绚丽的仿支付宝咻一咻雷达脉冲效果_Android

去年春节的时候支付宝推行的集福娃活动着实火的不能再火了,更给力的是春晚又可以全民参与咻一咻集福娃活动,集齐五福就可平分亿元大红包,只可惜没有敬业福--那时候在家没事写了个咻一咻插件,只要到了咻一咻的时间点插件就可以自动的点击咻一咻来咻红包,当时只是纯粹练习这部分技术代码没有公开,后续计划写篇关于插件这方面的文章,扯远了(*^__^*) --我们知道在支付宝的咻一咻页面有个雷达扩散的动画效果,当时感觉动画效果非常棒,于是私下尝试着实现了类似的效果,后来在github发现有大神也写有类似效果,于是读

Android自定义VIew实现卫星菜单效果浅析_Android

 一 概述: 最近一直致力于Android自定义VIew的学习,主要在看<android群英传>,还有CSDN博客鸿洋大神和wing大神的一些文章,写的很详细,自己心血来潮,学着写了个实现了类似卫星效果的一个自定义的View,分享到博客上,望各位指点一二.写的比较粗糙,见谅.(因为是在Linux系统下写的,效果图我直接用手机拍的,难看,大家讲究下就看个效果,勿喷). 先来看个效果图,有点不忍直视: 自定义VIew准备: (1)创建继承自View的类; (2)重写构造函数; (3)定义属性. (

Android自定义ViewGroup打造各种风格的SlidingMenu_Android

上篇给大家介绍QQ5.0侧滑菜单的视频课程,对于侧滑的时的动画效果的实现有了新的认识,似乎打通了任督二脉,目前可以实现任意效果的侧滑菜单了,感谢鸿洋大大!! 用的是HorizontalScrollView来实现的侧滑菜单功能,HorizontalScrollView的好处是为我们解决了滑动功能,处理了滑动冲突问题,让我们使用起来非常方便,但是滑动和冲突处理都是android中的难点,是我们应该掌握的知识点,掌握了这些,我们可以不依赖于系统的API,随心所欲打造我们想要的效果,因此这篇文章我将直接

Android自定义View实现弹性小球效果_Android

照例先看效果图 自定义代码示例 public class BezierView extends View { Paint paint;//画笔 Path path;//路径 int radius = 50;//圆的半径 int time = 100;//计数时长 int index; int offsetIndex; float viewX, viewY;//图形中心点坐标 float width;//屏幕宽度 float partWidth;//屏幕宽度的1/4 int paddingLeft

Android自定义ViewGroup打造各种风格的SlidingMenu

上篇给大家介绍QQ5.0侧滑菜单的视频课程,对于侧滑的时的动画效果的实现有了新的认识,似乎打通了任督二脉,目前可以实现任意效果的侧滑菜单了,感谢鸿洋大大!! 用的是HorizontalScrollView来实现的侧滑菜单功能,HorizontalScrollView的好处是为我们解决了滑动功能,处理了滑动冲突问题,让我们使用起来非常方便,但是滑动和冲突处理都是android中的难点,是我们应该掌握的知识点,掌握了这些,我们可以不依赖于系统的API,随心所欲打造我们想要的效果,因此这篇文章我将直接

Android自定义VIew实现卫星菜单效果浅析

一 概述: 最近一直致力于Android自定义VIew的学习,主要在看<android群英传>,还有CSDN博客鸿洋大神和wing大神的一些文章,写的很详细,自己心血来潮,学着写了个实现了类似卫星效果的一个自定义的View,分享到博客上,望各位指点一二.写的比较粗糙,见谅.(因为是在Linux系统下写的,效果图我直接用手机拍的,难看,大家讲究下就看个效果,勿喷). 先来看个效果图,有点不忍直视: 自定义VIew准备: (1)创建继承自View的类; (2)重写构造函数; (3)定义属性. (4

viewgroup 传参-android自定义ViewGroup的问题

问题描述 android自定义ViewGroup的问题 在名为Demo的activity中用到了一个继承ViewGroup的类MyView来布局,具体是这样的 在Demo的布局文件xml中, 在Demo的代码中 MyView scroll = (MyView) findViewById(R.id.view1); 在MyView中的构造函数 public MyView(Context context, AttributeSet attrs) { //各类操作 } 问题是Demo需要给scroll传