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

前面在学习鸿洋大神的一些自定义的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  

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

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索ViewGroup标签浮动
Android流式标签
自定义viewgroup、安卓自定义viewgroup、自定义滑动viewgroup、自定义viewgroup 刷新、自定义viewgroup实现,以便于您获取更多的相关知识。

时间: 2024-10-11 23:46:27

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

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

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

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实现标签流容器FlowLayout_Android

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

Android自定义View实现折线图效果_Android

下面就是结果图(每种状态用一个表情图片表示): 一.主页面的布局文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height=&quo

Android自定义HorizontalScrollView打造超强Gallery效果_Android

自从Gallery被谷歌废弃以后,Google推荐使用ViewPager和HorizontalScrollView来实现Gallery的效果.的确HorizontalScrollView可以实现Gallery的效果,但是HorizontalScrollView存在一个很大的问题,如果你仅是用来展示少量的图片,应该是没问题的,但是如果我希望HorizontalScrollView可以想ViewPager一样,既可以绑定数据集(动态改变图片),还能做到,不管多少图片都不会OOM(ViewPager内

Android自定义View实现水面上涨效果_Android

实现效果如下: 实现思路: 1.如何实现圆中水面上涨效果:利用Paint的setXfermode属性为PorterDuff.Mode.SRC_IN画出进度所在的矩形与圆的交集实现 2.如何水波纹效果:利用贝塞尔曲线,动态改变波峰值,实现"随着进度的增加,水波纹逐渐变小的效果" 话不多说,看代码. 首先是自定义属性值,有哪些可自定义属性值呢? 圆的背景颜色:circle_color,进度的颜色:progress_color,进度显示文字的颜色:text_color,进度文字的大小:tex

Android自定义View实现圆环交替效果_Android

下面请先看效果图: 看上去是不很炫的样子,它的实现上也不是很复杂,重点在与onDraw()方法的绘制. 首先是我们的attrs文件: <?xml version="1.0" encoding="utf-8"?> <resources> <attr name="firstColor" format="color"/> <attr name="secondColor"

Android自定义TextView实现文字倾斜效果_Android

前言 由于Android自带的TextView控件没有提供倾斜的(我暂时没有找到),我们可以自定义控件来实现,下面首先来看我们实现的效果图. TextView文字倾斜 其实实现很简单,下面我们来看实现步骤: 1.新建一个类 LeanTextView继承TextView public class LeanTextView extends TextView { public int getmDegrees() { return mDegrees; } public void setmDegrees(

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

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