docs: @Override
      protected void onLayout(boolean changed, int l, int t, int r, int b) {
  
          mLines.clear();
          mLineHeights.clear();
          mLineMargins.clear();
  
          int width = getWidth();
          int height = getHeight();
  
          int linesSum = getPaddingTop();
  
          int lineWidth = 0;
          int lineHeight = 0;
          List<View> lineViews = new ArrayList<View>();
  
          float horizontalGravityFactor;
          switch ((mGravity & Gravity.HORIZONTAL_GRAVITY_MASK)) {
              case Gravity.LEFT:
              default:
                  horizontalGravityFactor = 0;
                  break;
              case Gravity.CENTER_HORIZONTAL:
                  horizontalGravityFactor = .5f;
                  break;
              case Gravity.RIGHT:
                  horizontalGravityFactor = 1;
                  break;
          }
  
          for (int i = 0; i < getChildCount(); i++) {
  
              View child = getChildAt(i);
  
              if (child.getVisibility() == View.GONE) {
                  continue;
              }
  
              LayoutParams lp = (LayoutParams) child.getLayoutParams();
  
              int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
              int childHeight = child.getMeasuredHeight() + lp.bottomMargin + lp.topMargin;
  
              if (lineWidth + childWidth > width) {
                  mLineHeights.add(lineHeight);
                  mLines.add(lineViews);
                  mLineMargins.add((int) ((width - lineWidth) * horizontalGravityFactor) + getPaddingLeft());
  
                  linesSum += lineHeight;
  
                  lineHeight = 0;
                  lineWidth = 0;
                  lineViews = new ArrayList<View>();
              }
  
              lineWidth += childWidth;
              lineHeight = Math.max(lineHeight, childHeight);
              lineViews.add(child);
          }
  
          mLineHeights.add(lineHeight);
          mLines.add(lineViews);
          mLineMargins.add((int) ((width - lineWidth) * horizontalGravityFactor) + getPaddingLeft());
  
          linesSum += lineHeight;
  
          int verticalGravityMargin = 0;
          switch ((mGravity & Gravity.VERTICAL_GRAVITY_MASK)) {
              case Gravity.TOP:
              default:
                  break;
              case Gravity.CENTER_VERTICAL:
                  verticalGravityMargin = (height - linesSum) / 2;
                  break;
              case Gravity.BOTTOM:
                  verticalGravityMargin = height - linesSum;
                  break;
          }
  
          int numLines = mLines.size();
  
          int left;
          int top = getPaddingTop();
  
          for (int i = 0; i < numLines; i++) {
  
              lineHeight = mLineHeights.get(i);
              lineViews = mLines.get(i);
              left = mLineMargins.get(i);
  
              int children = lineViews.size();
  
              for (int j = 0; j < children; j++) {
  
                  View child = lineViews.get(j);
  
                  if (child.getVisibility() == View.GONE) {
                      continue;
                  }
  
                  LayoutParams lp = (LayoutParams) child.getLayoutParams();
  
                  // if height is match_parent we need to remeasure child to line height
                  if (lp.height == LayoutParams.MATCH_PARENT) {
                      int childWidthMode = MeasureSpec.AT_MOST;
                      int childWidthSize = lineWidth;
  
                      if (lp.width == LayoutParams.MATCH_PARENT) {
                          childWidthMode = MeasureSpec.EXACTLY;
                      } else if (lp.width >= 0) {
                          childWidthMode = MeasureSpec.EXACTLY;
                          childWidthSize = lp.width;
                      }
  
                      child.measure(
                              MeasureSpec.makeMeasureSpec(childWidthSize, childWidthMode),
                              MeasureSpec.makeMeasureSpec(lineHeight - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY)
                      );
                  }
  
                  int childWidth = child.getMeasuredWidth();
                  int childHeight = child.getMeasuredHeight();
  
                  int gravityMargin = 0;
  
                  if (Gravity.isVertical(lp.gravity)) {
                      switch (lp.gravity) {
                          case Gravity.TOP:
                          default:
                              break;
                          case Gravity.CENTER_VERTICAL:
                          case Gravity.CENTER:
                              gravityMargin = (lineHeight - childHeight - lp.topMargin - lp.bottomMargin) / 2;
                              break;
                          case Gravity.BOTTOM:
                              gravityMargin = lineHeight - childHeight - lp.topMargin - lp.bottomMargin;
                              break;
                      }
                  }
  
                  child.layout(left + lp.leftMargin,
                          top + lp.topMargin + gravityMargin + verticalGravityMargin,
                          left + childWidth + lp.leftMargin,
                          top + childHeight + lp.topMargin + gravityMargin + verticalGravityMargin);
  
                  left += childWidth + lp.leftMargin + lp.rightMargin;
  
              }
  
              top += lineHeight;
          }
  
      }