Personal homepage Demo download

rendering




Realize the effect drawing

Mind mapping




Mind mapping

First, the implementation of streaming layout

Implementation principle: The whole layout is divided into many rows of objects using object-oriented thought. Each row object manages the children in its own row, which is managed by collection.

1. Implementation of internal class Line

1.1 Define the basic attributes of the row
  • List: Manage the children in the line
  • MaxWidth: the maximum width of a row
  • UsedWidth: usedWidth
  • Height: the height of the row
  • Space: the space between children
  • Construct initializes maxWidth and space

      public Line(int maxWidth, int horizontalSpace) {
          this.maxWidth = maxWidth;
          this.space = horizontalSpace;
      }Copy the code
1.2 addView(View View) method implementation
  • Add a View to the collection of rows and update the width and height of the rows

    Public void addView(View View) {int childWidth = view.getMeasuredWidth(); int childHeight = view.getMeasuredHeight(); If (views.size() == 0) {childWidth > maxWidth {usedWidth = maxWidth; height = childHeight; } else { usedWidth = childWidth; height = childHeight; } } else { usedWidth += childWidth + space; height = childHeight > height ? childHeight : height; } // Add the child to the collection views.add(view); }Copy the code
1.3 canAddView(View View) method implementation
  • Determine if you can add children to the row, not if the width of the child is larger than the remaining width

    Public Boolean canAddView(View View) {if (views.size() == 0) {if (views.size() == 0) {if (views.size() == 0) {return  true; If (view.getMeasuredWidth() > (maxWidth-usedwidth-space)) {return false; if (view.getMeasuredWidth() > (maxWidth-usedwidth-space)) {return false; } // Return true can be added by default; }Copy the code

2. Measure the container (onMeasure method)

2.1 Get the width, calculate the maxWidth, and construct the incoming Line
  • The total width minus the left and right margins is the maximum width of the row

    Int width = MeasureSpec. GetSize (widthMeasureSpec); MMaxWidth = width-getPaddingLeft () -getpaddingright ();Copy the code
2.2 Cyclic acquisition of children for measurement
  • Get the total number of children, traverse to get each child, and then measure, and then add the child to the row set, and then add the row to the administrative row set

    / / * * * * * * * * * * * * * * * * * * * * measure children * * * * * * * * * * * * * * * * * * * * / / traverse from children int childCount = this. GetChildCount (); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); MeasureChild (childView, widthMeasureSpec, heightMeasureSpec); // Add the child to the collection of children in the management line. If (mCurrentLine == null) {mCurrentLine = new Line(mMaxWidth, HORIZONTAL_SPACE); // Add the child McUrrentline.addview (childView); // Add line mlines.add (mCurrentLine); } else {if (McUrrentline.canaddview (childView)) {// Add McUrrentline.addview (childView); } else {// add to next Line mCurrentLine = new Line(mMaxWidth, HORIZONTAL_SPACE); mCurrentLine.addView(childView); mLines.add(mCurrentLine); }}}Copy the code

2.3 Measure yourself

  • Since the width is bound to fill the entire screen, you only need to deal with the height of the line here, adding up all the line heights and the vertical margins to figure out the height

    / / * * * * * * * * * * * * * * * * * * * * measure their * * * * * * * * * * * * * * * * * * * * * / / measuring yourself only need to compute height, Width will definitely be filled with int height = getPaddingTop() + getPaddingBottom(); for (int i = 0; i < mLines.size(); I ++) {// Height of all lines += mlines.get (I).height; } // Height += (mlines.size () -1) * VERTICAL_SPACE; // Measure setMeasuredDimension(width, height);Copy the code

3. Specify the child display location (onLayout method implementation)

The location of the child is assigned to the row management, so the location of the child should be assigned to the row management. The container only needs to specify the position of the row.

  • Walk over all rows, let the row specify the child’s position, specify the height of the row

    @override protected void onLayout(Boolean changed, int l, int t, int r, int b) { L = getPaddingLeft(); l = getPaddingLeft(); t = getPaddingTop(); for (int i = 0; i < mLines.size(); I ++) {// get Line Line = lines.get (I); // Manage line.layout(t, l); // Update height t += line.height; if (i ! = mlines.size () -1) {// Not the last line to add spacing t += VERTICAL_SPACE; }}}Copy the code

4. Implementation of the layout method in Line (specify the location of the child)

  • Traverse to get each child, get the width and height of the child, calculate the size of the top, bottom, left and right, specify the position of the child, and then update the size of the left of the child

    Int measuredWidth = view.getMeasuredWidth(); int measuredWidth = view.getMeasuredWidth(); int measuredHeight = view.getMeasuredHeight(); / / to measure the measure (MeasureSpec makeMeasureSpec (measuredWidth + avg, MeasureSpec. EXACTLY), MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY)); MeasuredWidth = view.getMeasuredWidth(); int top = t; int left = l; int right = measuredWidth + left; int bottom = measuredHeight + top; View. layout(left, top, right, bottom); // Update data l += measuredWidth + space; }Copy the code

5. Details

  • After the first measurement, there are row objects in the row manager, and after each measurement, the next row is created, so there are many empty rows, so the collection needs to be emptied before the measurement.

      mLines.clear();
      mCurrentLine = null;Copy the code
  • If the last child in each row does not fit, put it on the next line, so that each line has a space, and then divide the space equally among each child in the row, respecifying its width.

    Int avg = (maxWidth - usedWidth)/views.size(); / / to measure the measure (MeasureSpec makeMeasureSpec (measuredWidth + avg, MeasureSpec. EXACTLY), MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY)); MeasuredWidth = view.getMeasuredWidth();Copy the code

6. Use custom attributes to make horizontal spacing and vertical spacing into attributes and specify them in the layout to enhance scalability

  • The attrs file specifies the attribute name

     
          
          
     Copy the code
  • Gets a property from the

    / / access to custom properties TypedArray array = context. ObtainStyledAttributes (attrs, R.s tyleable. FlowLayout); horizontal_space = array.getDimension(R.styleable.FlowLayout_width_space,0); vertical_space = array.getDimension(R.styleable.FlowLayout_height_space,0); array.recycle();Copy the code
  • Use attributes in a layout

      app:width_space="10dp"
      app:height_space="10dp"Copy the code
After the above steps, the FlowLayout is basically implemented, the next step is to use.

Use of streaming layout

  • Declare in layout

      
    
          
      Copy the code
  • Use in code

  • You iterate over the length of the data, create a TextView, and then set the TextView properties and background, including the colorful background, and finally add the TextView to the FlowLayout.

  • See Demo for specific codes

Personal homepage Demo download

The above is purely a summary of my daily work and study. If there is any mistake, please feel free to point it out. We can discuss and make progress together. If you think you’ve learned something, pleaseGithubGive it a thumbs up. Thank you.