Example #1
0
        public static void RecalculateSpanPositions(this TextView textView, Label element, SpannableString spannableString, SizeRequest finalSize)
        {
            if (element?.FormattedText?.Spans == null || element.FormattedText.Spans.Count == 0)
            {
                return;
            }

            var labelWidth = finalSize.Request.Width;

            if (labelWidth <= 0 || finalSize.Request.Height <= 0)
            {
                return;
            }

            if (spannableString == null || spannableString.IsDisposed())
            {
                return;
            }

            var layout = textView.Layout;

            if (layout == null)
            {
                return;
            }

            int         next             = 0;
            int         count            = 0;
            IList <int> totalLineHeights = new List <int>();

            for (int i = 0; i < spannableString.Length(); i = next)
            {
                var type = Java.Lang.Class.FromType(typeof(Java.Lang.Object));

                var span = element.FormattedText.Spans[count];

                count++;

                if (string.IsNullOrEmpty(span.Text))
                {
                    continue;
                }

                // find the next span
                next = spannableString.NextSpanTransition(i, spannableString.Length(), type);

                // get all spans in the range - Android can have overlapping spans
                var spans = spannableString.GetSpans(i, next, type);

                var startSpan = spans[0];
                var endSpan   = spans[spans.Length - 1];

                var startSpanOffset = spannableString.GetSpanStart(startSpan);
                var endSpanOffset   = spannableString.GetSpanEnd(endSpan);

                var thisLine  = layout.GetLineForOffset(endSpanOffset);
                var lineStart = layout.GetLineStart(thisLine);
                var lineEnd   = layout.GetLineEnd(thisLine);

                //If this is true, endSpanOffset has the value for another line that belong to the next span and not it self.
                //So it should be rearranged to value not pass the lineEnd.
                if (endSpanOffset > (lineEnd - lineStart))
                {
                    endSpanOffset = lineEnd;
                }

                var startX = layout.GetPrimaryHorizontal(startSpanOffset);
                var endX   = layout.GetPrimaryHorizontal(endSpanOffset);

                var startLine = layout.GetLineForOffset(startSpanOffset);
                var endLine   = layout.GetLineForOffset(endSpanOffset);

                double[] lineHeights = new double[endLine - startLine + 1];

                // calculate all the different line heights
                for (var lineCount = startLine; lineCount <= endLine; lineCount++)
                {
                    var lineHeight = layout.GetLineBottom(lineCount) - layout.GetLineTop(lineCount);
                    lineHeights[lineCount - startLine] = lineHeight;

                    if (totalLineHeights.Count <= lineCount)
                    {
                        totalLineHeights.Add(lineHeight);
                    }
                }

                var yaxis = 0.0;


                for (var line = startLine; line > 0; line--)
                {
                    yaxis += totalLineHeights[line];
                }

                ((ISpatialElement)span).Region = Region.FromLines(lineHeights, labelWidth, startX, endX, yaxis).Inflate(10);
            }
        }