search
HomeJavajavaTutorialAndroid custom ViewGroup implements label floating effect

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
How does platform independence benefit enterprise-level Java applications?How does platform independence benefit enterprise-level Java applications?May 03, 2025 am 12:23 AM

Java is widely used in enterprise-level applications because of its platform independence. 1) Platform independence is implemented through Java virtual machine (JVM), so that the code can run on any platform that supports Java. 2) It simplifies cross-platform deployment and development processes, providing greater flexibility and scalability. 3) However, it is necessary to pay attention to performance differences and third-party library compatibility and adopt best practices such as using pure Java code and cross-platform testing.

What role does Java play in the development of IoT (Internet of Things) devices, considering platform independence?What role does Java play in the development of IoT (Internet of Things) devices, considering platform independence?May 03, 2025 am 12:22 AM

JavaplaysasignificantroleinIoTduetoitsplatformindependence.1)Itallowscodetobewrittenonceandrunonvariousdevices.2)Java'secosystemprovidesusefullibrariesforIoT.3)ItssecurityfeaturesenhanceIoTsystemsafety.However,developersmustaddressmemoryandstartuptim

Describe a scenario where you encountered a platform-specific issue in Java and how you resolved it.Describe a scenario where you encountered a platform-specific issue in Java and how you resolved it.May 03, 2025 am 12:21 AM

ThesolutiontohandlefilepathsacrossWindowsandLinuxinJavaistousePaths.get()fromthejava.nio.filepackage.1)UsePaths.get()withSystem.getProperty("user.dir")andtherelativepathtoconstructthefilepath.2)ConverttheresultingPathobjecttoaFileobjectifne

What are the benefits of Java's platform independence for developers?What are the benefits of Java's platform independence for developers?May 03, 2025 am 12:15 AM

Java'splatformindependenceissignificantbecauseitallowsdeveloperstowritecodeonceandrunitonanyplatformwithaJVM.This"writeonce,runanywhere"(WORA)approachoffers:1)Cross-platformcompatibility,enablingdeploymentacrossdifferentOSwithoutissues;2)Re

What are the advantages of using Java for web applications that need to run on different servers?What are the advantages of using Java for web applications that need to run on different servers?May 03, 2025 am 12:13 AM

Java is suitable for developing cross-server web applications. 1) Java's "write once, run everywhere" philosophy makes its code run on any platform that supports JVM. 2) Java has a rich ecosystem, including tools such as Spring and Hibernate, to simplify the development process. 3) Java performs excellently in performance and security, providing efficient memory management and strong security guarantees.

How does the JVM contribute to Java's 'write once, run anywhere' (WORA) capability?How does the JVM contribute to Java's 'write once, run anywhere' (WORA) capability?May 02, 2025 am 12:25 AM

JVM implements the WORA features of Java through bytecode interpretation, platform-independent APIs and dynamic class loading: 1. Bytecode is interpreted as machine code to ensure cross-platform operation; 2. Standard API abstract operating system differences; 3. Classes are loaded dynamically at runtime to ensure consistency.

How do newer versions of Java address platform-specific issues?How do newer versions of Java address platform-specific issues?May 02, 2025 am 12:18 AM

The latest version of Java effectively solves platform-specific problems through JVM optimization, standard library improvements and third-party library support. 1) JVM optimization, such as Java11's ZGC improves garbage collection performance. 2) Standard library improvements, such as Java9's module system reducing platform-related problems. 3) Third-party libraries provide platform-optimized versions, such as OpenCV.

Explain the process of bytecode verification performed by the JVM.Explain the process of bytecode verification performed by the JVM.May 02, 2025 am 12:18 AM

The JVM's bytecode verification process includes four key steps: 1) Check whether the class file format complies with the specifications, 2) Verify the validity and correctness of the bytecode instructions, 3) Perform data flow analysis to ensure type safety, and 4) Balancing the thoroughness and performance of verification. Through these steps, the JVM ensures that only secure, correct bytecode is executed, thereby protecting the integrity and security of the program.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.