@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++) {
ViewGroup child=(ViewGroup)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<>();
}
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 (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;
}
}

@ 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 ++ ) { ViewGroup child = ( ViewGroup ) 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 < > ( ) ; } 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 ( 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 ; } }
position all children within this layout .
