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; } }