protected override void OnLayout(bool changed, int l, int t, int r, int b)
        {
            int count = this.ChildCount;

            for (int i = 0; i < count; i++)
            {
                View child            = this.GetChildAt(i);
                CustomLayoutParams lp = (CustomLayoutParams)child.LayoutParameters;
                child.Layout(lp.x + lp.LeftMargin, lp.y + lp.TopMargin, lp.x + lp.LeftMargin + child.MeasuredWidth, lp.y + lp.TopMargin + child.MeasuredHeight);
            }
        }
        private void ApplyGravityToLine(LineDefinition line)
        {
            int viewCount = line.Views.Count;

            if (viewCount <= 0)
            {
                return;
            }

            float totalWeight = 0;

            foreach (View prev in line.Views)
            {
                CustomLayoutParams plp = (CustomLayoutParams)prev.LayoutParameters;
                totalWeight += this.GetWeight(plp);
            }

            View lastChild = line.Views[viewCount - 1];
            CustomLayoutParams lastChildLayoutParams = (CustomLayoutParams)lastChild.LayoutParameters;
            int excessLength = line.LineLength - (lastChildLayoutParams.Length + lastChildLayoutParams.InlineStartLength);
            int excessOffset = 0;

            foreach (View child in line.Views)
            {
                CustomLayoutParams layoutParams = (CustomLayoutParams)child.LayoutParameters;

                float        weight      = this.GetWeight(layoutParams);
                GravityFlags gravity     = this.GetGravity(layoutParams);
                int          extraLength = (int)Math.Round((double)(excessLength * weight / totalWeight));

                int childLength    = layoutParams.Length + layoutParams.SpacingLength;
                int childThickness = layoutParams.Thickness + layoutParams.SpacingThickness;

                Rect container = new Rect();
                container.Top    = 0;
                container.Left   = excessOffset;
                container.Right  = childLength + extraLength + excessOffset;
                container.Bottom = line.LineThickness;

                Rect result = new Rect();
                Android.Views.Gravity.Apply(gravity, childLength, childThickness, container, result);

                excessOffset += extraLength;
                layoutParams.InlineStartLength    = result.Left + layoutParams.InlineStartLength;
                layoutParams.InlineStartThickness = result.Top;
                layoutParams.Length    = result.Width() - layoutParams.SpacingLength;
                layoutParams.Thickness = result.Height() - layoutParams.SpacingThickness;
            }
        }
 private void ApplyPositionsToViews(LineDefinition line)
 {
     foreach (View child in line.Views)
     {
         CustomLayoutParams layoutParams = (CustomLayoutParams)child.LayoutParameters;
         if (this.config.Orientation == HORIZONTAL)
         {
             layoutParams.SetPosition(this.PaddingLeft + line.LineStartLength + layoutParams.InlineStartLength, this.PaddingTop + line.LineStartThickness + layoutParams.InlineStartThickness);
             child.Measure(MeasureSpec.MakeMeasureSpec(layoutParams.Length, MeasureSpecMode.Exactly), MeasureSpec.MakeMeasureSpec(layoutParams.Thickness, MeasureSpecMode.Exactly));
         }
         else
         {
             layoutParams.SetPosition(this.PaddingLeft + line.LineStartThickness + layoutParams.InlineStartThickness, this.PaddingTop + line.LineStartLength + layoutParams.InlineStartLength);
             child.Measure(MeasureSpec.MakeMeasureSpec(layoutParams.Thickness, MeasureSpecMode.Exactly), MeasureSpec.MakeMeasureSpec(layoutParams.Length, MeasureSpecMode.Exactly));
         }
     }
 }
        private void CalculateLinesAndChildPosition(IList <LineDefinition> lines)
        {
            int prevLinesThickness = 0;

            foreach (LineDefinition line in lines)
            {
                line.AddLineStartThickness(prevLinesThickness);
                prevLinesThickness += line.LineThickness;
                int prevChildThickness = 0;
                foreach (View child in line.Views)
                {
                    CustomLayoutParams layoutParams = (CustomLayoutParams)child.LayoutParameters;
                    layoutParams.InlineStartLength = prevChildThickness;
                    prevChildThickness            += layoutParams.Length + layoutParams.SpacingLength;
                }
            }
        }
        protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            int sizeWidth  = MeasureSpec.GetSize(widthMeasureSpec) - this.PaddingRight - this.PaddingLeft;
            int sizeHeight = MeasureSpec.GetSize(heightMeasureSpec) - this.PaddingTop - this.PaddingBottom;

            MeasureSpecMode modeWidth  = MeasureSpec.GetMode(widthMeasureSpec);
            MeasureSpecMode modeHeight = MeasureSpec.GetMode(heightMeasureSpec);

            int controlMaxLength    = this.config.Orientation == HORIZONTAL ? sizeWidth : sizeHeight;
            int controlMaxThickness = this.config.Orientation == HORIZONTAL ? sizeHeight : sizeWidth;

            MeasureSpecMode modeLength    = this.config.Orientation == HORIZONTAL ? modeWidth : modeHeight;
            MeasureSpecMode modeThickness = this.config.Orientation == HORIZONTAL ? modeHeight : modeWidth;

            lines.Clear();
            LineDefinition currentLine = new LineDefinition(controlMaxLength, config);

            lines.Add(currentLine);

            int count = this.ChildCount;

            for (int i = 0; i < count; i++)
            {
                View child = this.GetChildAt(i);
                if (child.Visibility == ViewStates.Gone)
                {
                    continue;
                }

                CustomLayoutParams lp = (CustomLayoutParams)child.LayoutParameters;

                child.Measure(GetChildMeasureSpec(widthMeasureSpec, this.PaddingLeft + this.PaddingRight, lp.Width), GetChildMeasureSpec(heightMeasureSpec, this.PaddingTop + this.PaddingBottom, lp.Height));

                lp.ClearCalculatedFields(this.config.Orientation);
                if (this.config.Orientation == FlowLayout.HORIZONTAL)
                {
                    lp.Length    = child.MeasuredWidth;
                    lp.Thickness = child.MeasuredHeight;
                }
                else
                {
                    lp.Length    = child.MeasuredHeight;
                    lp.Thickness = child.MeasuredWidth;
                }

                bool newLine = lp.newLine || (modeLength != MeasureSpecMode.Unspecified && !currentLine.CanFit(child));
                if (newLine)
                {
                    currentLine = new LineDefinition(controlMaxLength, config);
                    if (this.config.Orientation == VERTICAL && this.config.Direction == LAYOUT_DIRECTION_RTL)
                    {
                        lines.Insert(0, currentLine);
                    }
                    else
                    {
                        lines.Add(currentLine);
                    }
                }

                if (this.config.Orientation == HORIZONTAL && this.config.Direction == LAYOUT_DIRECTION_RTL)
                {
                    currentLine.AddView(0, child);
                }
                else
                {
                    currentLine.AddView(child);
                }
            }

            this.CalculateLinesAndChildPosition(lines);

            int contentLength = 0;

            foreach (LineDefinition l in lines)
            {
                contentLength = Math.Max(contentLength, l.LineLength);
            }
            int contentThickness = currentLine.LineStartThickness + currentLine.LineThickness;

            int realControlLength    = this.FindSize(modeLength, controlMaxLength, contentLength);
            int realControlThickness = this.FindSize(modeHeight, controlMaxThickness, contentThickness);

            this.ApplyGravityToLines(lines, realControlLength, realControlThickness);

            foreach (LineDefinition line in lines)
            {
                this.ApplyGravityToLine(line);
                this.ApplyPositionsToViews(line);
            }

            /* need to take padding into account */
            int totalControlWidth  = this.PaddingLeft + this.PaddingRight;
            int totalControlHeight = this.PaddingBottom + this.PaddingTop;

            if (this.config.Orientation == HORIZONTAL)
            {
                totalControlWidth  += contentLength;
                totalControlHeight += contentThickness;
            }
            else
            {
                totalControlWidth  += contentThickness;
                totalControlHeight += contentLength;
            }
            this.SetMeasuredDimension(ResolveSize(totalControlWidth, widthMeasureSpec), ResolveSize(totalControlHeight, heightMeasureSpec));
        }
        private void DrawDebugInfo(Canvas canvas, View child)
        {
            if (!this.config.DebugDraw)
            {
                return;
            }

            Paint childPaint   = this.CreatePaint(Color.ParseColor("#ffffff00"));
            Paint newLinePaint = this.CreatePaint(Color.ParseColor("#ffff0000"));

            CustomLayoutParams lp = (CustomLayoutParams)child.LayoutParameters;

            if (lp.RightMargin > 0)
            {
                float x = child.Right;
                float y = child.Top + child.Height / 2.0f;
                canvas.DrawLine(x, y, x + lp.RightMargin, y, childPaint);
                canvas.DrawLine(x + lp.RightMargin - 4.0f, y - 4.0f, x + lp.RightMargin, y, childPaint);
                canvas.DrawLine(x + lp.RightMargin - 4.0f, y + 4.0f, x + lp.RightMargin, y, childPaint);
            }

            if (lp.LeftMargin > 0)
            {
                float x = child.Left;
                float y = child.Top + child.Height / 2.0f;
                canvas.DrawLine(x, y, x - lp.LeftMargin, y, childPaint);
                canvas.DrawLine(x - lp.LeftMargin + 4.0f, y - 4.0f, x - lp.LeftMargin, y, childPaint);
                canvas.DrawLine(x - lp.LeftMargin + 4.0f, y + 4.0f, x - lp.LeftMargin, y, childPaint);
            }

            if (lp.BottomMargin > 0)
            {
                float x = child.Left + child.Width / 2.0f;
                float y = child.Bottom;
                canvas.DrawLine(x, y, x, y + lp.BottomMargin, childPaint);
                canvas.DrawLine(x - 4.0f, y + lp.BottomMargin - 4.0f, x, y + lp.BottomMargin, childPaint);
                canvas.DrawLine(x + 4.0f, y + lp.BottomMargin - 4.0f, x, y + lp.BottomMargin, childPaint);
            }

            if (lp.TopMargin > 0)
            {
                float x = child.Left + child.Width / 2.0f;
                float y = child.Top;
                canvas.DrawLine(x, y, x, y - lp.TopMargin, childPaint);
                canvas.DrawLine(x - 4.0f, y - lp.TopMargin + 4.0f, x, y - lp.TopMargin, childPaint);
                canvas.DrawLine(x + 4.0f, y - lp.TopMargin + 4.0f, x, y - lp.TopMargin, childPaint);
            }

            if (lp.newLine)
            {
                if (this.config.Orientation == HORIZONTAL)
                {
                    float x = child.Left;
                    float y = child.Top + child.Height / 2.0f;
                    canvas.DrawLine(x, y - 6.0f, x, y + 6.0f, newLinePaint);
                }
                else
                {
                    float x = child.Left + child.Width / 2.0f;
                    float y = child.Top;
                    canvas.DrawLine(x - 6.0f, y, x + 6.0f, y, newLinePaint);
                }
            }
        }
 private float GetWeight(CustomLayoutParams lp)
 {
     return(lp.WeightSpecified() ? lp.weight : this.config.WeightDefault);
 }
 private GravityFlags GetGravity(CustomLayoutParams lp)
 {
     return(lp.GravitySpecified() ? lp.gravity : this.config.Gravity);
 }
        protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            base.OnMeasure(widthMeasureSpec, heightMeasureSpec);

            int sizeWidth  = MeasureSpec.GetSize(widthMeasureSpec) - PaddingLeft - PaddingRight;
            int sizeHeight = MeasureSpec.GetSize(heightMeasureSpec);

            MeasureSpecMode modeWidth  = MeasureSpec.GetMode(widthMeasureSpec);
            MeasureSpecMode modeHeight = MeasureSpec.GetMode(heightMeasureSpec);

            int width  = 0;
            int height = PaddingTop + PaddingBottom;

            int lineWidth  = 0;
            int lineHeight = 0;

            int childCount = ChildCount;

            for (int i = 0; i < childCount; i++)
            {
                View child     = GetChildAt(i);
                bool lastChild = i == childCount - 1;

                if (child.Visibility == ViewStates.Gone)
                {
                    if (lastChild)
                    {
                        width   = Math.Max(width, lineWidth);
                        height += lineHeight;
                    }

                    continue;
                }

                MeasureChildWithMargins(child, widthMeasureSpec, lineWidth, heightMeasureSpec, height);

                CustomLayoutParams lp = (CustomLayoutParams)child.LayoutParameters;

                MeasureSpecMode childWidthMode = MeasureSpecMode.AtMost;
                int             childWidthSize = sizeWidth;

                MeasureSpecMode childHeightMode = MeasureSpecMode.AtMost;
                int             childHeightSize = sizeHeight;

                if (lp.Width == LayoutParams.MatchParent)
                {
                    childWidthMode  = MeasureSpecMode.Exactly;
                    childWidthSize -= lp.LeftMargin + lp.RightMargin;
                }
                else if (lp.Width >= 0)
                {
                    childWidthMode = MeasureSpecMode.Exactly;
                    childWidthSize = lp.Width;
                }

                if (lp.Height >= 0)
                {
                    childHeightMode = MeasureSpecMode.Exactly;
                    childHeightSize = lp.Height;
                }
                else if (modeHeight == MeasureSpecMode.Unspecified)
                {
                    childHeightMode = MeasureSpecMode.Unspecified;
                    childHeightSize = 0;
                }

                child.Measure(MeasureSpec.MakeMeasureSpec(childWidthSize, childWidthMode), MeasureSpec.MakeMeasureSpec(childHeightSize, childHeightMode));

                int childWidth = child.MeasuredWidth + lp.LeftMargin + lp.RightMargin;

                if (lineWidth + childWidth > sizeWidth)
                {
                    width     = Math.Max(width, lineWidth);
                    lineWidth = childWidth;

                    height    += lineHeight;
                    lineHeight = child.MeasuredHeight + lp.TopMargin + lp.BottomMargin;
                }
                else
                {
                    lineWidth += childWidth;
                    lineHeight = Math.Max(lineHeight, child.MeasuredHeight + lp.TopMargin + lp.BottomMargin);
                }

                if (lastChild)
                {
                    width   = Math.Max(width, lineWidth);
                    height += lineHeight;
                }
            }

            width += PaddingLeft + PaddingRight;

            SetMeasuredDimension((modeWidth == MeasureSpecMode.Exactly) ? sizeWidth : width, (modeHeight == MeasureSpecMode.Exactly) ? sizeHeight : height);
        }
        protected override void OnLayout(bool changed, int l, int t, int r, int b)
        {
            mLines.Clear();
            mLineHeights.Clear();
            mLineMargins.Clear();

            int width  = Width;
            int height = Height;

            int linesSum = PaddingTop;

            int          lineWidth  = 0;
            int          lineHeight = 0;
            IList <View> lineViews  = new List <View>();

            float horizontalGravityFactor;

            switch ((mGravity & GravityFlags.HorizontalGravityMask))
            {
            case GravityFlags.Left:
            default:
                horizontalGravityFactor = 0;
                break;

            case GravityFlags.CenterHorizontal:
                horizontalGravityFactor = .5f;
                break;

            case GravityFlags.Right:
                horizontalGravityFactor = 1;
                break;
            }

            for (int i = 0; i < ChildCount; i++)
            {
                View child = GetChildAt(i);

                if (child.Visibility == ViewStates.Gone)
                {
                    continue;
                }

                CustomLayoutParams lp = (CustomLayoutParams)child.LayoutParameters;

                int childWidth  = child.MeasuredWidth + lp.LeftMargin + lp.RightMargin;
                int childHeight = child.MeasuredHeight + lp.BottomMargin + lp.TopMargin;

                if (lineWidth + childWidth > width)
                {
                    mLineHeights.Add(lineHeight);
                    mLines.Add(lineViews);
                    mLineMargins.Add((int)((width - lineWidth) * horizontalGravityFactor) + PaddingLeft);

                    linesSum += lineHeight;

                    lineHeight = 0;
                    lineWidth  = 0;
                    lineViews  = new List <View>();
                }

                lineWidth += childWidth;
                lineHeight = Math.Max(lineHeight, childHeight);
                lineViews.Add(child);
            }

            mLineHeights.Add(lineHeight);
            mLines.Add(lineViews);
            mLineMargins.Add((int)((width - lineWidth) * horizontalGravityFactor) + PaddingLeft);

            linesSum += lineHeight;

            int verticalGravityMargin = 0;

            switch ((mGravity & GravityFlags.VerticalGravityMask))
            {
            case GravityFlags.Top:
            default:
                break;

            case GravityFlags.CenterVertical:
                verticalGravityMargin = (height - linesSum) / 2;
                break;

            case GravityFlags.Bottom:
                verticalGravityMargin = height - linesSum;
                break;
            }

            int numLines = mLines.Count;

            int left;
            int top = PaddingTop;

            for (int i = 0; i < numLines; i++)
            {
                lineHeight = mLineHeights[i];
                lineViews  = mLines[i];
                left       = mLineMargins[i];

                int children = lineViews.Count;

                for (int j = 0; j < children; j++)
                {
                    View child = lineViews[j];

                    if (child.Visibility == ViewStates.Gone)
                    {
                        continue;
                    }

                    CustomLayoutParams lp = (CustomLayoutParams)child.LayoutParameters;

                    // if height is match_parent we need to remeasure child to line height
                    if (lp.Height == LayoutParams.MatchParent)
                    {
                        MeasureSpecMode childWidthMode = MeasureSpecMode.AtMost;
                        int             childWidthSize = lineWidth;

                        if (lp.Width == LayoutParams.MatchParent)
                        {
                            childWidthMode = MeasureSpecMode.Exactly;
                        }
                        else if (lp.Width >= 0)
                        {
                            childWidthMode = MeasureSpecMode.Exactly;
                            childWidthSize = lp.Width;
                        }

                        child.Measure(MeasureSpec.MakeMeasureSpec(childWidthSize, childWidthMode), MeasureSpec.MakeMeasureSpec(lineHeight - lp.TopMargin - lp.BottomMargin, MeasureSpecMode.Exactly));
                    }

                    int childWidth  = child.MeasuredWidth;
                    int childHeight = child.MeasuredHeight;

                    int gravityMargin = 0;

                    if (Android.Views.Gravity.IsVertical(lp.gravity))
                    {
                        switch (lp.gravity)
                        {
                        case GravityFlags.Top:
                        default:
                            break;

                        case GravityFlags.CenterVertical:
                        case GravityFlags.Center:
                            gravityMargin = (lineHeight - childHeight - lp.TopMargin - lp.BottomMargin) / 2;
                            break;

                        case GravityFlags.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;
            }
        }