internal static float WidthFit(ICharSequence text, TextPaint paint, int lines, float min, float max, int availWidth, int availHeight) { if (availWidth > int.MaxValue / 3) { if (availHeight > int.MaxValue / 3) { return(max); } var fontMetrics = paint.GetFontMetrics(); var fontLineHeight = fontMetrics.Descent * FontScale - fontMetrics.Ascent * FontScale; var fontLeading = System.Math.Abs(fontMetrics.Bottom * FontScale - fontMetrics.Descent * FontScale); var fontPixelSize = paint.TextSize * FontScale; var lineHeightRatio = fontLineHeight / fontPixelSize; var leadingRatio = fontLeading / fontPixelSize; float ans = ((availHeight / (lines + leadingRatio * (lines - 1))) / lineHeightRatio - 0.1f); return(System.Math.Min(ans, max)); } var result = ZeroLinesFit(text, paint, min, max, availWidth, availHeight); float step = (result - min) / 5; if (step > 0.05f) { result = DescendingWidthFit(text, paint, lines, min, result, availWidth, availHeight, step); while (step > 0.25f) { step /= 5; result = DescendingWidthFit(text, paint, lines, result, result + step * 5, availWidth, availHeight, step); } } return(result); }
internal static float ZeroLinesFit(ICharSequence text, TextPaint paint, float min, float max, int availWidth, int availHeight) { if (availHeight > int.MaxValue / 3) { return(max); } if (availWidth > int.MaxValue / 3) { var fontMetrics = paint.GetFontMetrics(); var fontLineHeight = fontMetrics.Descent - fontMetrics.Ascent; //var fontLeading = System.Math.Abs(fontMetrics.Bottom - fontMetrics.Descent); var fontPixelSize = paint.TextSize; var lineHeightRatio = fontLineHeight / fontPixelSize; //var leadingRatio = fontLeading / fontPixelSize; var result = (availHeight / lineHeightRatio - 0.1f); return(System.Math.Min(result, max)); } if (max - min < Precision) { return(min); } float mid = (max + min) / 2.0f; paint.TextSize = mid * Scale; var layout = new StaticLayout(text, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true); var lineCount = layout.LineCount; var height = layout.Height - layout.BottomPadding + layout.TopPadding; if (height > availHeight) { return(ZeroLinesFit(text, paint, min, mid, availWidth, availHeight)); } if (height < availHeight) { return(ZeroLinesFit(text, paint, mid, max, availWidth, availHeight)); } float maxLineWidth = 0; for (int i = 0; i < lineCount; i++) { if (layout.GetLineWidth(i) > maxLineWidth) { maxLineWidth = layout.GetLineWidth(i); } } if (maxLineWidth > availWidth) { return(ZeroLinesFit(text, paint, min, mid, availWidth, availHeight)); } if (maxLineWidth < availWidth) { return(ZeroLinesFit(text, paint, mid, max, availWidth, availHeight)); } return(mid); }
internal static float ZeroLinesFit(ICharSequence text, TextPaint paint, float min, float max, int availWidth, int availHeight, float lineHeightMultiplier) { if (availHeight >= 238609294) { return(max); } if (availWidth >= 238609294) { var fontMetrics = paint.GetFontMetrics(); var fontLineHeight = fontMetrics.Descent * FontScale - fontMetrics.Ascent * FontScale; var fontPixelSize = paint.TextSize * FontScale; var lineHeightRatio = fontLineHeight / fontPixelSize; var result = (availHeight / lineHeightRatio - 0.1f); return(System.Math.Min(result, max)); } if (max - min < Precision) { return(min); } float mid = (max + min) / 2.0f; paint.TextSize = mid * Scale; using (var layout = TextExtensions.StaticLayout(text, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, lineHeightMultiplier, 0.0f, true)) { var lineCount = layout.LineCount; var height = layout.Height - layout.BottomPadding + layout.TopPadding; if (height > availHeight) { return(ZeroLinesFit(text, paint, min, mid, availWidth, availHeight, lineHeightMultiplier)); } if (height < availHeight) { return(ZeroLinesFit(text, paint, mid, max, availWidth, availHeight, lineHeightMultiplier)); } float maxLineWidth = 0; for (int i = 0; i < lineCount; i++) { if (layout.GetLineWidth(i) > maxLineWidth) { maxLineWidth = layout.GetLineWidth(i); } } if (maxLineWidth > availWidth) { return(ZeroLinesFit(text, paint, min, mid, availWidth, availHeight, lineHeightMultiplier)); } if (maxLineWidth < availWidth) { return(ZeroLinesFit(text, paint, mid, max, availWidth, availHeight, lineHeightMultiplier)); } return(mid); } }
/// <summary>Define paints.</summary> private void InitPaint() { // Round rectangle paint _strokePaint = new Paint { Color = _selectedColor.ToColor(), AntiAlias = true, StrokeWidth = _strokeWidth }; _strokePaint.SetStyle(Paint.Style.Stroke); // Selected paint _fillPaint = new Paint { Color = _selectedColor.ToColor() }; _strokePaint.AntiAlias = true; _fillPaint.SetStyle(Paint.Style.FillAndStroke); // Selected text paint _selectedTextPaint = new TextPaint(PaintFlags.AntiAlias) { TextSize = _textSize, Color = unchecked ((int)0xffffffff).ToColor() }; _strokePaint.AntiAlias = true; // Unselected text paint _unselectedTextPaint = new TextPaint(PaintFlags.AntiAlias) { TextSize = _textSize, Color = _selectedColor.ToColor() }; _strokePaint.AntiAlias = true; _textHeightOffset = -(_selectedTextPaint.Ascent() + _selectedTextPaint.Descent()) * 0.5f; _fontMetrics = _selectedTextPaint.GetFontMetrics(); }
internal static float WidthFit(ICharSequence text, TextPaint paint, int lines, float min, float max, int availWidth, int availHeight) { //System.Diagnostics.Debug.WriteLine("F9PTextView.WidthFit: availWidth=["+availWidth+"] availHeight=["+availHeight+"]"); if (availWidth > int.MaxValue / 3) { if (availHeight > int.MaxValue / 3) { return(max); } var fontMetrics = paint.GetFontMetrics(); var fontLineHeight = fontMetrics.Descent - fontMetrics.Ascent; var fontLeading = System.Math.Abs(fontMetrics.Bottom - fontMetrics.Descent); var fontPixelSize = paint.TextSize; var lineHeightRatio = fontLineHeight / fontPixelSize; var leadingRatio = fontLeading / fontPixelSize; float ans = ((availHeight / (lines + leadingRatio * (lines - 1))) / lineHeightRatio - 0.1f); if (ans > max) { ans = max; } return(ans); } var result = ZeroLinesFit(text, paint, min, max, availWidth, availHeight); float step = (result - min) / 5; if (step > 0.05f) { result = DescendingWidthFit(text, paint, lines, min, result, availWidth, availHeight, step); while (step > 0.25f) { step /= 5; result = DescendingWidthFit(text, paint, lines, result, result + step * 5, availWidth, availHeight, step); } } return(result); }
public override void Draw(Canvas canvas) { base.Draw(canvas); TextPaint paint = new TextPaint(); paint.AntiAlias = true; paint.SetTypeface(Control.Typeface); paint.TextSize = myFontSize * scaledDensity; paint.Color = Android.Graphics.Color.Red; Paint.FontMetrics metrics = paint.GetFontMetrics(); Rect bounds = new Rect(); paint.GetTextBounds(Element.Text, 0, Element.Text.Length, bounds); canvas.DrawText( Element.Text, 0.5f * MeasuredWidth - bounds.Left - 0.5f * bounds.Width(), 0.5f * MeasuredHeight - metrics.Ascent - 0.5f * (metrics.Bottom - metrics.Top), paint ); }
//bool _truncating; internal static StaticLayout Truncate(string text, F9PFormattedString baseFormattedString, TextPaint paint, int availWidth, int availHeight, AutoFit fit, LineBreakMode lineBreakMode, ref int lines, ref ICharSequence textFormatted) { StaticLayout layout = null; var fontMetrics = paint.GetFontMetrics(); var fontLineHeight = fontMetrics.Descent - fontMetrics.Ascent; var fontLeading = System.Math.Abs(fontMetrics.Bottom - fontMetrics.Descent); textFormatted = ((ICharSequence)baseFormattedString?.ToSpannableString()) ?? new Java.Lang.String(text); if (lines > 0) { if (baseFormattedString != null) { layout = new StaticLayout(textFormatted, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true); if (layout.Height > availHeight) { var visibleLines = (int)((fontLeading + availHeight) / (fontLineHeight + fontLeading)); if (visibleLines < lines) { lines = visibleLines; } } if (layout.LineCount > lines && lines > 0) { var secondToLastEnd = lines > 1 ? layout.GetLineEnd(lines - 2) : 0; var start = lines > 1 ? layout.GetLineStart(layout.LineCount - 2) : 0; switch (lineBreakMode) { case LineBreakMode.HeadTruncation: textFormatted = StartTruncatedFormatted(baseFormattedString, paint, secondToLastEnd, start, layout.GetLineEnd(layout.LineCount - 1), availWidth); break; case LineBreakMode.MiddleTruncation: textFormatted = MidTruncatedFormatted(baseFormattedString, paint, secondToLastEnd, layout.GetLineStart(lines - 1), (layout.GetLineEnd(lines - 1) + layout.GetLineStart(lines - 1)) / 2 - 1, start, layout.GetLineEnd(layout.LineCount - 1), availWidth); break; case LineBreakMode.TailTruncation: textFormatted = EndTruncatedFormatted(baseFormattedString, paint, secondToLastEnd, layout.GetLineStart(lines - 1), layout.GetLineEnd(layout.LineCount - 1), availWidth); break; default: //textFormatted = baseFormattedString.ToSpannableString(EllipsePlacement.None, 0, 0, layout.GetLineEnd(lines - 1)); textFormatted = TruncatedFormatted(baseFormattedString, paint, secondToLastEnd, layout.GetLineStart(lines - 1), layout.GetLineEnd(layout.LineCount - 1), availWidth); break; } } } else { layout = new StaticLayout(text, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true); if (layout.Height > availHeight) { var visibleLines = (int)((fontLeading + availHeight) / (fontLineHeight + fontLeading)); if (visibleLines < lines) { lines = visibleLines; } } if (layout.LineCount > lines && lines > 0) { var secondToLastEnd = lines > 1 ? layout.GetLineEnd(lines - 2) : 0; var start = lines > 1 ? layout.GetLineStart(layout.LineCount - 2) : 0; switch (lineBreakMode) { case LineBreakMode.HeadTruncation: text = StartTruncatedLastLine(text, paint, secondToLastEnd, start, layout.GetLineEnd(layout.LineCount - 1), availWidth); break; case LineBreakMode.MiddleTruncation: text = MidTruncatedLastLine(text, paint, secondToLastEnd, layout.GetLineStart(lines - 1), (layout.GetLineEnd(lines - 1) + layout.GetLineStart(lines - 1)) / 2 - 1, start, layout.GetLineEnd(layout.LineCount - 1), availWidth); break; case LineBreakMode.TailTruncation: text = EndTruncatedLastLine(text, paint, secondToLastEnd, layout.GetLineStart(lines - 1), layout.GetLineEnd(layout.LineCount - 1), availWidth); break; default: text = text.Substring(0, layout.GetLineEnd(lines - 1)); break; } textFormatted = new Java.Lang.String(text); } } } return(new StaticLayout(textFormatted, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true)); }
#pragma warning disable IDE0060 // Remove unused parameter internal static StaticLayout Truncate(string text, Forms9Patch.F9PFormattedString baseFormattedString, TextPaint paint, int availWidth, int availHeight, AutoFit fit, LineBreakMode lineBreakMode, float lineHeightMultiplier, ref int lines, ref ICharSequence textFormatted) #pragma warning restore IDE0060 // Remove unused parameter { StaticLayout layout = null; var fontMetrics = paint.GetFontMetrics(); var fontLineHeight = fontMetrics.Descent - fontMetrics.Ascent; var fontLeading = System.Math.Abs(fontMetrics.Bottom - fontMetrics.Descent); textFormatted = ((ICharSequence)baseFormattedString?.ToSpannableString()) ?? new Java.Lang.String(text); if (lines > 0) { if (baseFormattedString != null) { layout = TextExtensions.StaticLayout(textFormatted, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, lineHeightMultiplier, 0.0f, true); if (layout.Height > availHeight) { var visibleLines = (int)((fontLeading + availHeight) / (fontLineHeight + fontLeading)); if (visibleLines < lines) { lines = visibleLines; } } if (layout.LineCount > lines && lines > 0) { var secondToLastEnd = lines > 1 ? layout.GetLineEnd(lines - 2) : 0; var start = lines > 1 ? layout.GetLineStart(layout.LineCount - 2) : 0; textFormatted?.Dispose(); switch (lineBreakMode) { case LineBreakMode.HeadTruncation: textFormatted = StartTruncatedFormatted(baseFormattedString, paint, secondToLastEnd, start, layout.GetLineEnd(layout.LineCount - 1), availWidth, lineHeightMultiplier); break; case LineBreakMode.MiddleTruncation: textFormatted = MidTruncatedFormatted(baseFormattedString, paint, secondToLastEnd, layout.GetLineStart(lines - 1), (layout.GetLineEnd(lines - 1) + layout.GetLineStart(lines - 1)) / 2 - 1, start, layout.GetLineEnd(layout.LineCount - 1), availWidth, lineHeightMultiplier); break; case LineBreakMode.TailTruncation: textFormatted = EndTruncatedFormatted(baseFormattedString, paint, secondToLastEnd, layout.GetLineStart(lines - 1), layout.GetLineEnd(layout.LineCount - 1), availWidth, lineHeightMultiplier); break; default: textFormatted = TruncatedFormatted(baseFormattedString, paint, secondToLastEnd, layout.GetLineStart(lines - 1), layout.GetLineEnd(layout.LineCount - 1), availWidth, lineHeightMultiplier); break; } } } else { layout = TextExtensions.StaticLayout(text, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, lineHeightMultiplier, 0.0f, true); if (layout.Height > availHeight) { var visibleLines = (int)((fontLeading + availHeight) / (fontLineHeight + fontLeading)); if (visibleLines < lines) { lines = visibleLines; } } if (layout.LineCount > lines && lines > 0) { var secondToLastEnd = lines > 1 ? layout.GetLineEnd(lines - 2) : 0; var start = lines > 1 ? layout.GetLineStart(layout.LineCount - 2) : 0; switch (lineBreakMode) { case LineBreakMode.HeadTruncation: text = StartTruncatedLastLine(text, paint, secondToLastEnd, start, layout.GetLineEnd(layout.LineCount - 1), availWidth, lineHeightMultiplier); break; case LineBreakMode.MiddleTruncation: text = MidTruncatedLastLine(text, paint, secondToLastEnd, layout.GetLineStart(lines - 1), (layout.GetLineEnd(lines - 1) + layout.GetLineStart(lines - 1)) / 2 - 1, start, layout.GetLineEnd(layout.LineCount - 1), availWidth, lineHeightMultiplier); break; case LineBreakMode.TailTruncation: text = EndTruncatedLastLine(text, paint, secondToLastEnd, layout.GetLineStart(lines - 1), layout.GetLineEnd(layout.LineCount - 1), availWidth, lineHeightMultiplier); break; default: text = text.Substring(0, layout.GetLineEnd(lines - 1)); break; } textFormatted?.Dispose(); textFormatted = new Java.Lang.String(text); } } } var result = TextExtensions.StaticLayout(textFormatted, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, lineHeightMultiplier, 0.0f, true); layout?.Dispose(); //textFormatted?.Dispose(); // this causes Bc3.Keypad to break! return(result); }