Home  >  Article  >  Java  >  Android custom ViewGroup implements label floating effect

Android custom ViewGroup implements label floating effect

高洛峰
高洛峰Original
2017-01-16 17:04:471605browse

I was studying some customized View articles by Master Hongyang earlier, and saw the custom ViewGroup to implement floating labels. I took a preliminary look at his ideas and combined my own ideas to complete my own custom ViewGroup for floating labels. The current implementation can dynamically add labels and be clickable. The rendering is as follows:

Android custom ViewGroup implements label floating effect

1. Idea
First, measure the width and height of the ViewGroup in the onMeasure method. The focus is on processing when our customized ViewGroup is set to wrap_content. In this case, the problem is how to measure its size. When our customized ViewGroup is set to wrap_content, we need to let the sub-View measure itself first. After the sub-View is measured, the width and height of the sub-View can be obtained through the getMeasuredWidth and getMeasureHeight methods of the sub-View. Every time before measuring a sub-View, you need to determine whether the current row can accommodate the sub-View if the sub-View is added. If not, you need to open a new row and record the maximum height of the current row.
In the onLayout method, the core role is to place the position of each sub-View, that is, to find the two points on the box model for each sub-View in the ViewGroup, which are the upper left corner and the lower right corner, that is, point (l, t ) and point (r, b), the two points are determined, and the position of the sub-View is also determined.

2. Implementation
Once you have the basic idea, you can try to implement it. The code is as follows:
Customized 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("闲逛的蚂蚁");
 }
 
}

and above That’s the entire content of this article. I hope it will be helpful to everyone’s learning. I also hope everyone will support the PHP Chinese website.

For more articles related to Android custom ViewGroup implementing label floating effect, please pay attention to the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn