Esempio n. 1
0
        static double FindDefaultLineHeight(this NativeLabel control, int start, int length)
        {
            if (length == 0)
            {
                return(0.0);
            }

            var textStorage = new NSTextStorage();

#if __MOBILE__
            textStorage.SetString(control.AttributedText.Substring(start, length));
#else
            textStorage.SetString(control.AttributedStringValue.Substring(start, length));
#endif
            var layoutManager = new NSLayoutManager();
            textStorage.AddLayoutManager(layoutManager);

            var textContainer = new NSTextContainer(size: new SizeF(float.MaxValue, float.MaxValue))
            {
                LineFragmentPadding = 0
            };
            layoutManager.AddTextContainer(textContainer);

            var rect = GetCharacterBounds(new NSRange(0, 1), layoutManager, textContainer);
            return(rect.Bottom - rect.Top);
        }
Esempio n. 2
0
        private void UpdateHyperlinkLayout()
        {
            // Configure textContainer
            var textContainer = new NSTextContainer();

            textContainer.LineFragmentPadding  = 0;
            textContainer.LineBreakMode        = LineBreakMode;
            textContainer.MaximumNumberOfLines = (nuint)Lines;
            textContainer.Size = _drawRect.Size;

            // Configure layoutManager
            _layoutManager = new NSLayoutManager();
            _layoutManager.AddTextContainer(textContainer);

            // Configure textStorage
            var textStorage = new NSTextStorage();

            textStorage.SetString(GetAttributedText(NSAttributedStringTarget.NSTextStorage));
            textStorage.AddLayoutManager(_layoutManager);

            if (FeatureConfiguration.TextBlock.ShowHyperlinkLayouts)
            {
                textStorage.AddAttributes(
                    new UIStringAttributes()
                {
                    ForegroundColor = UIColor.Red
                },
                    new NSRange(0, textStorage.Length)
                    );
            }
        }
Esempio n. 3
0
        int IndexAtPoint(Point point)
        {
            if (Control is UILabel control)
            {
                var cgPoint = new CGPoint(point.X, point.Y - control.Frame.Y);

                // init text storage
                var textStorage = new NSTextStorage();
                var attrText    = new NSAttributedString(control.AttributedText);
                textStorage.SetString(attrText);

                // init layout manager
                var layoutManager = new NSLayoutManager();
                textStorage.AddLayoutManager(layoutManager);

                // init text container
                var textContainer = new NSTextContainer(new CGSize(control.Frame.Width, control.Frame.Height * 2))
                {
                    LineFragmentPadding  = 0,
                    MaximumNumberOfLines = (nuint)_currentDrawState.Lines,
                    LineBreakMode        = UILineBreakMode.WordWrap,
                    Size = new CGSize(control.Frame.Width, control.Frame.Height * 2)
                };
                layoutManager.AddTextContainer(textContainer);
                layoutManager.AllowsNonContiguousLayout = true;

                var characterIndex = layoutManager.GetCharacterIndex(cgPoint, textContainer);
                return((int)characterIndex);
            }
            return(-1);
        }
        private static string DetectTappedUrl(UIGestureRecognizer tap, UILabel control)
        {
            CGRect             bounds         = control.Bounds;
            NSAttributedString attributedText = control.AttributedText;

            // Setup containers
            using var textContainer = new NSTextContainer(bounds.Size)
                  {
                      LineFragmentPadding  = 0,
                      LineBreakMode        = control.LineBreakMode,
                      MaximumNumberOfLines = (nuint)control.Lines
                  };

            using var layoutManager = new NSLayoutManager();
            layoutManager.AddTextContainer(textContainer);

            using var textStorage = new NSTextStorage();
            textStorage.SetString(attributedText);

            using var fontAttributeName = new NSString("NSFont");
            var textRange = new NSRange(0, control.AttributedText.Length);

            textStorage.AddAttribute(fontAttributeName, control.Font, textRange);
            textStorage.AddLayoutManager(layoutManager);
            CGRect textBoundingBox = layoutManager.GetUsedRectForTextContainer(textContainer);
        private string DetectTappedUrl(UIGestureRecognizer tap, UILabel label, IEnumerable <LinkData> linkList)
        {
            // Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
            var layoutManager = new NSLayoutManager();
            var textContainer = new NSTextContainer();
            var textStorage   = new NSTextStorage();

            textStorage.SetString(label.AttributedText);

            // Configure layoutManager and textStorage
            layoutManager.AddTextContainer(textContainer);
            textStorage.AddLayoutManager(layoutManager);

            // Configure textContainer
            textContainer.LineFragmentPadding  = 0;
            textContainer.LineBreakMode        = label.LineBreakMode;
            textContainer.MaximumNumberOfLines = (nuint)label.Lines;
            var labelSize = label.Bounds.Size;

            textContainer.Size = labelSize;

            // Find the tapped character location and compare it to the specified range
            var locationOfTouchInLabel = tap.LocationInView(label);
            var textBoundingBox        = layoutManager.GetUsedRectForTextContainer(textContainer);
            var textContainerOffset    = new CGPoint((labelSize.Width - textBoundingBox.Size.Width) * 0.0 - textBoundingBox.Location.X,
                                                     (labelSize.Height - textBoundingBox.Size.Height) * 0.0 - textBoundingBox.Location.Y);

            nfloat labelX;

            switch (Element.HorizontalTextAlignment)
            {
            case TextAlignment.End:
                labelX = locationOfTouchInLabel.X - (labelSize.Width - textBoundingBox.Size.Width);
                break;

            case TextAlignment.Center:
                labelX = locationOfTouchInLabel.X - (labelSize.Width - textBoundingBox.Size.Width) / 2;
                break;

            default:
                labelX = locationOfTouchInLabel.X;
                break;
            }
            var locationOfTouchInTextContainer = new CGPoint(labelX - textContainerOffset.X, locationOfTouchInLabel.Y - textContainerOffset.Y);

            nfloat partialFraction  = 0;
            var    indexOfCharacter = (nint)layoutManager.CharacterIndexForPoint(locationOfTouchInTextContainer, textContainer, ref partialFraction);

            foreach (var link in linkList)
            {
                // Xamarin version of NSLocationInRange?
                if ((indexOfCharacter >= link.Range.Location) && (indexOfCharacter < link.Range.Location + link.Range.Length))
                {
                    return(link.Url);
                }
            }
            return(null);
        }
Esempio n. 6
0
        // NOTE: this method only works with single line UILabels, or multi-line labels with left aligned text
        // Potential fix found on timbroder's comment on https://stackoverflow.com/questions/1256887/create-tap-able-links-in-the-nsattributedstring-of-a-uilabel
        // Based on https://stackoverflow.com/questions/1256887/create-tap-able-links-in-the-nsattributedstring-of-a-uilabel
        // Based on https://samwize.com/2016/03/04/how-to-create-multiple-tappable-links-in-a-uilabel/
        /// <summary>
        /// Determines whether the tap is within the NSRange targetRange. Returns true if so, otherwise returns false.
        /// </summary>
        /// <returns><c>true</c>, if tap was within the targetRange of the label, <c>false</c> otherwise.</returns>
        /// <param name="label">The label containing the text.</param>
        /// <param name="targetRange">The target range of the tappable text within the label.</param>
        /// <param name="gestureRecognizer">Gesture recognizer.</param>
        /// <param name="textAlignment">Text alignment of the label.</param>
        public static bool DidTapAttributedTextInLabel(UILabel label, NSRange targetRange, UIGestureRecognizer gestureRecognizer, UITextAlignment textAlignment)
        {
            NSLayoutManager layoutManager = new NSLayoutManager();
            NSTextContainer textContainer = new NSTextContainer(CGSize.Empty);
            NSTextStorage   textStorage   = new NSTextStorage();

            textStorage.SetString(label.AttributedText);

            // Configure layoutManager and textStorage
            layoutManager.AddTextContainer(textContainer);
            textStorage.AddLayoutManager(layoutManager);

            // Configure textContainer
            textContainer.LineFragmentPadding  = 0.0f;
            textContainer.LineBreakMode        = label.LineBreakMode;
            textContainer.MaximumNumberOfLines = (System.nuint)label.Lines;

            CGSize labelSize = label.Bounds.Size;

            textContainer.Size = labelSize;

            // Find the tapped character location and compare it to the specified range
            CGPoint locationOfTouchInLabel = gestureRecognizer.LocationInView(label);
            CGRect  textBoundingBox        = layoutManager.GetUsedRectForTextContainer(textContainer);

            // Change based on the UITextAlignment enum
            float multiplier;

            if (textAlignment == UITextAlignment.Center)
            {
                multiplier = 0.5f;
            }
            else if (textAlignment == UITextAlignment.Right)
            {
                multiplier = 1.0f;
            }
            else
            {
                // textAlignment is Left, Natural, or Justified
                multiplier = 0.0f;
            }

            CGPoint textContainerOffset = new CGPoint(
                ((labelSize.Width - textBoundingBox.Size.Width) * multiplier - textBoundingBox.Location.X),
                ((labelSize.Height - textBoundingBox.Size.Height) * multiplier - textBoundingBox.Location.Y)
                );
            CGPoint locationOfTouchInTextContainer = new CGPoint(locationOfTouchInLabel.X - textContainerOffset.X, locationOfTouchInLabel.Y - textContainerOffset.Y);
            nfloat  partialFraction  = 0;
            int     indexOfCharacter = (int)layoutManager.CharacterIndexForPoint(locationOfTouchInTextContainer, textContainer, ref partialFraction);

            // Xamarin version of the function NSLocationInRange (Swift equivalent is to call ```NSLocationInRange(indexOfCharacter, targetRange);``` )
            // Credit to https://forums.xamarin.com/discussion/56484/need-to-put-html-into-a-label
            bool isInRange = (indexOfCharacter >= targetRange.Location) && (indexOfCharacter <= targetRange.Location + targetRange.Length);

            return(isInRange);
        }
Esempio n. 7
0
        int IndexAtPoint(Point point)
        {
            var cgPoint = new CGPoint(point.X, point.Y - Control.Frame.Y);

            // init text storage
            var textStorage = new NSTextStorage();
            //if (Control.AttributedText != null)
            var attrText = new NSAttributedString(Control.AttributedText);

            textStorage.SetString(attrText);

            /*
             *          else
             *          {
             *                  var attrString = new NSMutableAttributedString(Control.Text);
             *                  attrString.AddAttribute(UIStringAttributeKey.Font, Control.Font, new NSRange(0, Control.Text.Length));
             *                  textStorage.SetString(attrString);
             *          }
             */

            // init layout manager
            var layoutManager = new NSLayoutManager();

            textStorage.AddLayoutManager(layoutManager);

            // init text container
            var textContainer = new NSTextContainer(new CGSize(Control.Frame.Width, Control.Frame.Height * 2));

            textContainer.LineFragmentPadding  = 0;
            textContainer.MaximumNumberOfLines = (nuint)ControlLines;
            textContainer.LineBreakMode        = UILineBreakMode.WordWrap;//Control.LineBreakMode;

            //if (Control.LineBreakMode == UILineBreakMode.TailTruncation || Control.LineBreakMode == UILineBreakMode.HeadTruncation || Control.LineBreakMode == UILineBreakMode.MiddleTruncation)
            //	textContainer.LineBreakMode = UILineBreakMode.WordWrap;

            textContainer.Size = new CGSize(Control.Frame.Width, Control.Frame.Height * 2);
            layoutManager.AddTextContainer(textContainer);
            layoutManager.AllowsNonContiguousLayout = true;

            //layoutManager.SetTextContainer(textContainer,new NSRange(0,Control.AttributedText.Length));

            //layoutManager.UsesFontLeading = true;
            //layoutManager.EnsureLayoutForCharacterRange(new NSRange(0,Control.AttributedText.Length));
            //layoutManager.EnsureLayoutForTextContainer(textContainer);
            nfloat partialFraction = 0;
            var    characterIndex  = layoutManager.CharacterIndexForPoint(cgPoint, textContainer, ref partialFraction);

            //[self.layoutManager drawGlyphsForGlyphRange:NSMakeRange(0, self.textStorage.length) atPoint:CGPointMake(0, 0)];
            //layoutManager.DrawGlyphs(new NSRange(0,Control.AttributedText.Length),Control.Frame.Location);

            return((int)characterIndex);
        }
        public void GetGlyphsTest()
        {
            TestRuntime.AssertSystemVersion(ApplePlatform.iOS, 7, 0, throwIfOtherPlatform: false);

            using (var txt = new NSTextStorage()) {
                var str = "hello world\n\t";
                txt.SetString(new NSAttributedString(str));
                using (var lm = new NSLayoutManager()) {
                    lm.TextStorage = txt;
                    var glyphs          = new short[str.Length];
                    var props           = new NSGlyphProperty [glyphs.Length];
                    var charIndexBuffer = new nuint [glyphs.Length];
                    var bidiLevelBuffer = new byte [glyphs.Length];
                    lm.GetGlyphs(new NSRange(0, str.Length), glyphs, props, charIndexBuffer, bidiLevelBuffer);
                    Assert.That(glyphs, Is.EqualTo(new short [] { 75, 72, 79, 79, 82, 3, 90, 82, 85, 79, 71, -1, -1 }), "glyphs");
                    Assert.That(props, Is.EqualTo(new NSGlyphProperty [] {
                        0,
                        0,
                        0,
                        0,
                        0,
                        NSGlyphProperty.Elastic,
                        0,
                        0,
                        0,
                        0,
                        0,
                        NSGlyphProperty.ControlCharacter,
                        NSGlyphProperty.ControlCharacter
                    }), "props");
                    Assert.That(charIndexBuffer, Is.EqualTo(new nuint [] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }), "charIndexBuffer");
                    Assert.That(bidiLevelBuffer, Is.EqualTo(new byte [str.Length]), "bidiLevelBuffer");
                }
            }

            using (var txt = new NSTextStorage()) {
                var str = "hello world\n\t";
                txt.SetString(new NSAttributedString(str));
                using (var lm = new NSLayoutManager()) {
                    lm.TextStorage = txt;
                    var glyphs          = new short[str.Length];
                    var charIndexBuffer = new nuint [glyphs.Length];
                    var bidiLevelBuffer = new byte [glyphs.Length];
                    lm.GetGlyphs(new NSRange(0, str.Length), glyphs, null, charIndexBuffer, bidiLevelBuffer);
                    Assert.That(glyphs, Is.EqualTo(new short [] { 75, 72, 79, 79, 82, 3, 90, 82, 85, 79, 71, -1, -1 }), "glyphs");

                    Assert.That(charIndexBuffer, Is.EqualTo(new nuint [] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }), "charIndexBuffer");
                    Assert.That(bidiLevelBuffer, Is.EqualTo(new byte [str.Length]), "bidiLevelBuffer");
                }
            }
        }
Esempio n. 9
0
        private CGSize textSize(string str, NSDictionary attributes)
        {
            // The three components
            var storage   = new NSTextStorage();
            var layout    = new NSLayoutManager();
            var container = new NSTextContainer();

            // Bind them
            layout.AddTextContainer(container);
            storage.AddLayoutManager(layout);

            storage.SetString(new NSAttributedString(str, attributes));

            // Compute
            layout.GetGlyphRange(container);

            // Get size
            CGSize size = layout.GetUsedRectForTextContainer(container).Size;

            return(size);
        }
Esempio n. 10
0
        private int GetCharacterIndexAtPoint(Point point)
        {
            if (!_drawRect.Contains(point))
            {
                return(-1);
            }

            // Configure textContainer
            var textContainer = new NSTextContainer();

            textContainer.LineFragmentPadding  = 0;
            textContainer.LineBreakMode        = LineBreakMode;
            textContainer.MaximumNumberOfLines = (nuint)Lines;
            textContainer.Size = _drawRect.Size;

            // Configure layoutManager
            var layoutManager = new NSLayoutManager();

            layoutManager.AddTextContainer(textContainer);

            // Configure textStorage
            var textStorage = new NSTextStorage();

            textStorage.SetString(AttributedText);
            textStorage.AddLayoutManager(layoutManager);
            textStorage.SetAttributes(
                new UIStringAttributes()
            {
                Font = Font
            },
                new NSRange(0, textStorage.Length)
                );

            // Find the tapped character's index
            var partialFraction      = (nfloat)0;
            var pointInTextContainer = new CGPoint(point.X - _drawRect.X, point.Y - _drawRect.Y);
            var characterIndex       = (int)layoutManager.CharacterIndexForPoint(pointInTextContainer, textContainer, ref partialFraction);

            return(characterIndex);
        }
Esempio n. 11
0
            void ResetAttributes(NSColor foregroundColorOverride = null)
            {
                // clear user attributes
                TextStorage.SetAttributes(new NSDictionary(), new NSRange(0, TextStorage.Length));

                var r = new NSRange(0, Text.Length);

                TextStorage.SetString(new NSAttributedString(Text));
                TextStorage.SetAlignment(TextAlignment.ToNSTextAlignment(), r);

                if (Font != null)
                {
                    // set a global font
                    TextStorage.AddAttribute(NSStringAttributeKey.Font, Font, r);
                }

                // paragraph style
                TextContainer.LineBreakMode = TextTrimming == TextTrimming.WordElipsis ? NSLineBreakMode.TruncatingTail : NSLineBreakMode.ByWordWrapping;
                var pstyle = NSParagraphStyle.DefaultParagraphStyle.MutableCopy() as NSMutableParagraphStyle;

                pstyle.Alignment = TextAlignment.ToNSTextAlignment();
                if (TextTrimming == TextTrimming.WordElipsis)
                {
                    pstyle.LineBreakMode = NSLineBreakMode.TruncatingTail;
                }
                TextStorage.AddAttribute(NSStringAttributeKey.ParagraphStyle, pstyle, r);

                // set foreground color override
                if (foregroundColorOverride != null)
                {
                    TextStorage.AddAttribute(NSStringAttributeKey.ForegroundColor, foregroundColorOverride, r);
                }

                // restore user attributes
                foreach (var att in Attributes)
                {
                    AddAttributeInternal(att);
                }
            }
Esempio n. 12
0
        public CGRect boundingRectForCharacter(NSRange range)
        {
            NSTextStorage textStorage = new NSTextStorage();

            textStorage.SetString(this.AttributedText);

            NSLayoutManager layoutManager = new NSLayoutManager();

            textStorage.AddLayoutManager(layoutManager);

            NSTextContainer textContainer = new NSTextContainer(this.Bounds.Size);

            textContainer.LineFragmentPadding = 0f;

            layoutManager.AddTextContainer(textContainer);

            NSRange glyphRange;

            glyphRange = layoutManager.CharacterRangeForGlyphRange(range);

            return(layoutManager.BoundingRectForGlyphRange(glyphRange, textContainer));
        }
Esempio n. 13
0
        private void UpdateTypography()
        {
            _attributedString = GetAttributedText();

            if (UseLayoutManager)
            {
                // Configure textContainer
                _textContainer = new NSTextContainer();
                _textContainer.LineFragmentPadding  = 0;
                _textContainer.LineBreakMode        = GetLineBreakMode();
                _textContainer.MaximumNumberOfLines = (nuint)GetLines();

                // Configure layoutManager
                _layoutManager = new NSLayoutManager();
                _layoutManager.AddTextContainer(_textContainer);

                // Configure textStorage
                _textStorage = new NSTextStorage();
                _textStorage.AddLayoutManager(_layoutManager);
                _textStorage.SetString(_attributedString);
            }
        }
Esempio n. 14
0
        public void GetGlyphsTest()
        {
            if (!TestRuntime.CheckSystemAndSDKVersion(7, 0))
            {
                Assert.Ignore("requires iOS7+");
            }

            using (var txt = new NSTextStorage()) {
                var str = "hello world\n\t";
                txt.SetString(new NSAttributedString(str));
                using (var lm = new NSLayoutManager()) {
                    lm.TextStorage = txt;
                    var glyphs          = new short[str.Length];
                    var props           = new NSGlyphProperty [glyphs.Length];
                    var charIndexBuffer = new nuint [glyphs.Length];
                    var bidiLevelBuffer = new byte [glyphs.Length];
                    lm.GetGlyphs(new NSRange(0, str.Length), glyphs, props, charIndexBuffer, bidiLevelBuffer);
                    Assert.That(glyphs, Is.EqualTo(new short [] { 75, 72, 79, 79, 82, 3, 90, 82, 85, 79, 71, -1, -1 }), "glyphs");
                    Assert.That(props, Is.EqualTo(new NSGlyphProperty [] {
                        0,
                        0,
                        0,
                        0,
                        0,
                        NSGlyphProperty.Elastic,
                        0,
                        0,
                        0,
                        0,
                        0,
                        NSGlyphProperty.ControlCharacter,
                        NSGlyphProperty.ControlCharacter
                    }), "props");
                    Assert.That(charIndexBuffer, Is.EqualTo(new nuint [] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }), "charIndexBuffer");
                    Assert.That(bidiLevelBuffer, Is.EqualTo(new byte [str.Length]), "bidiLevelBuffer");
                }
            }
        }
Esempio n. 15
0
        bool didTapAttributedTextInLabel(UITapGestureRecognizer tap, UILabel label, NSRange targetRange)
        {
            var layoutManager = new NSLayoutManager();
            var textContainer = new NSTextContainer(CGSize.Empty);
            var textStorage   = new NSTextStorage();

            textStorage.SetString(label.AttributedText);

            layoutManager.AddTextContainer(textContainer);
            textStorage.AddLayoutManager(layoutManager);


            textContainer.LineFragmentPadding  = 0;
            textContainer.LineBreakMode        = label.LineBreakMode;
            textContainer.MaximumNumberOfLines = (nuint)label.Lines;
            var labelSize = label.Bounds.Size;

            textContainer.Size = labelSize;


            var locationOfTouchInLabel = tap.LocationInView(label);
            var textBoundingBox        = layoutManager.GetUsedRectForTextContainer(textContainer);
            var textContainerOffset    = new CGPoint((labelSize.Width - textBoundingBox.Size.Width) * 0.5 - textBoundingBox.Location.X,
                                                     (labelSize.Height - textBoundingBox.Size.Height) * 0.5 - textBoundingBox.Location.Y);

            var locationOfTouchInTextContainer = new CGPoint(locationOfTouchInLabel.X - textContainerOffset.X,
                                                             locationOfTouchInLabel.Y - textContainerOffset.Y);

            nfloat partialFraction  = 1;
            var    indexOfCharacter = layoutManager.CharacterIndexForPoint(locationOfTouchInTextContainer, textContainer, ref partialFraction);

            if (((nint)indexOfCharacter >= targetRange.Location) && ((nint)indexOfCharacter < targetRange.Location + targetRange.Length))
            {
                return(true);
            }

            return(false);
        }
        private NSRange?AttributedTextRangeForPoint(CGPoint point)
        {
            var layoutManager = new NSLayoutManager();
            var textContainer = new NSTextContainer(CGSize.Empty)
            {
                LineFragmentPadding  = 0.0f,
                LineBreakMode        = LineBreakMode,
                MaximumNumberOfLines = (nuint)Lines,
                Size = Bounds.Size
            };

            layoutManager.AddTextContainer(textContainer);
            var textStorage = new NSTextStorage();

            textStorage.SetString(AttributedText);
            textStorage.AddLayoutManager(layoutManager);

            var textBoundingBox     = layoutManager.GetUsedRectForTextContainer(textContainer);
            var textContainerOffset = new CGPoint(
                (Bounds.Width - textBoundingBox.Width) * 0.5f - textBoundingBox.GetMinX(),
                (Bounds.Height - textBoundingBox.Height) * 0.5f - textBoundingBox.GetMinY());

            var locationOfTouchInTextContainer = new CGPoint(point.X - textContainerOffset.X,
                                                             point.Y - textContainerOffset.Y);
            var frac             = new nfloat(0.0f);
            var indexOfCharacter = layoutManager.CharacterIndexForPoint(locationOfTouchInTextContainer,
                                                                        textContainer, ref frac);

            foreach (var pair in _handlerDictionary)
            {
                var range = pair.Key;
                if (range.LocationInRange((int)indexOfCharacter))
                {
                    return(range);
                }
            }
            return(null);
        }
Esempio n. 17
0
        public static void RecalculateSpanPositions(this NativeLabel control, Label element)
        {
            if (element == null)
            {
                return;
            }

            if (element.TextType == TextType.Html)
            {
                return;
            }

            if (element?.FormattedText?.Spans == null ||
                element.FormattedText.Spans.Count == 0)
            {
                return;
            }

            var finalSize = control.Frame;

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

#if __MOBILE__
            var inline = control.AttributedText;
#else
            var inline = control.AttributedStringValue;
#endif
            var range = new NSRange(0, inline.Length);

            NSTextStorage textStorage = new NSTextStorage();
            textStorage.SetString(inline);

            var layoutManager = new NSLayoutManager();
            textStorage.AddLayoutManager(layoutManager);

            var textContainer = new NSTextContainer(size: finalSize.Size)
            {
                LineFragmentPadding = 0
            };

            layoutManager.AddTextContainer(textContainer);

            var labelWidth = finalSize.Width;

            var currentLocation = 0;

            for (int i = 0; i < element.FormattedText.Spans.Count; i++)
            {
                var span = element.FormattedText.Spans[i];

                var location = currentLocation;
                var length   = span.Text?.Length ?? 0;

                if (length == 0)
                {
                    continue;
                }

                var startRect = GetCharacterBounds(new NSRange(location, 1), layoutManager, textContainer);
                var endRect   = GetCharacterBounds(new NSRange(location + length, 1), layoutManager, textContainer);

                var startLineHeight = startRect.Bottom - startRect.Top;
                var endLineHeight   = endRect.Bottom - endRect.Top;

                var defaultLineHeight = control.FindDefaultLineHeight(location, length);

                var yaxis       = startRect.Top;
                var lineHeights = new List <double>();

                while ((endRect.Bottom - yaxis) > 0.001)
                {
                    double lineHeight;
                    if (yaxis == startRect.Top)                     // First Line
                    {
                        lineHeight = startRect.Bottom - startRect.Top;
                    }
                    else if (yaxis != endRect.Top)                     // Middle Line(s)
                    {
                        lineHeight = defaultLineHeight;
                    }
                    else                     // Bottom Line
                    {
                        lineHeight = endRect.Bottom - endRect.Top;
                    }
                    lineHeights.Add(lineHeight);
                    yaxis += (float)lineHeight;
                }

                ((ISpatialElement)span).Region = Region.FromLines(lineHeights.ToArray(), finalSize.Width, startRect.X, endRect.X, startRect.Top).Inflate(10);

                // update current location
                currentLocation += length;
            }
        }
        private string DetectTappedUrl(UIGestureRecognizer tap, UILabel label, IEnumerable <LinkData> linkList)
        {
            var layoutManager = new NSLayoutManager();
            var textContainer = new NSTextContainer();
            var textStorage   = new NSTextStorage();

            textStorage.SetString(label.AttributedText);

            layoutManager.AddTextContainer(textContainer);
            textStorage.AddLayoutManager(layoutManager);

            textContainer.LineFragmentPadding  = 0;
            textContainer.LineBreakMode        = label.LineBreakMode;
            textContainer.MaximumNumberOfLines = (nuint)label.Lines;
            var labelSize = label.Bounds.Size;

            textContainer.Size = labelSize;

            var locationOfTouchInLabel = tap.LocationInView(label);
            var textBoundingBox        = layoutManager.GetUsedRectForTextContainer(textContainer);
            var textContainerOffset    = new CGPoint(
                (labelSize.Width - textBoundingBox.Size.Width) * 0.0 - textBoundingBox.Location.X,
                (labelSize.Height - textBoundingBox.Size.Height) * 0.0 - textBoundingBox.Location.Y);

            nfloat labelX;

            switch (Element.HorizontalTextAlignment)
            {
            case TextAlignment.End:
                labelX = locationOfTouchInLabel.X - (labelSize.Width - textBoundingBox.Size.Width);
                break;

            case TextAlignment.Center:
                labelX = locationOfTouchInLabel.X - (labelSize.Width - textBoundingBox.Size.Width) / 2;
                break;

            default:
                labelX = locationOfTouchInLabel.X;
                break;
            }

            var locationOfTouchInTextContainer = new CGPoint(labelX - textContainerOffset.X,
                                                             locationOfTouchInLabel.Y - textContainerOffset.Y);

            nfloat partialFraction  = 0;
            var    indexOfCharacter = (nint)layoutManager.CharacterIndexForPoint(locationOfTouchInTextContainer,
                                                                                 textContainer, ref partialFraction);

            nint scaledIndexOfCharacter = 0;

            if (label.Font.Name == "NeoSans-Light")
            {
                scaledIndexOfCharacter = (nint)(indexOfCharacter * 1.13);
            }

            if (label.Font.Name.StartsWith("HelveticaNeue", StringComparison.InvariantCulture))
            {
                scaledIndexOfCharacter = (nint)(indexOfCharacter * 1.02);
            }

            foreach (var link in linkList)
            {
                var rangeLength = link.Range.Length;
                var tolerance   = 0;
                if (label.Font.Name == "NeoSans-Light")
                {
                    rangeLength      = (nint)(rangeLength * 1.13);
                    tolerance        = 25;
                    indexOfCharacter = scaledIndexOfCharacter;
                }

                if (label.Font.Name.StartsWith("HelveticaNeue", StringComparison.InvariantCulture))
                {
                    if (link.Range.Location > 2000)
                    {
                        indexOfCharacter = scaledIndexOfCharacter;
                    }
                }

                // Xamarin version of NSLocationInRange?
                if ((indexOfCharacter >= (link.Range.Location - tolerance)) &&
                    (indexOfCharacter < (link.Range.Location + rangeLength + tolerance)))
                {
                    return(link.Url);
                }
            }

            return(null);
        }
Esempio n. 19
0
 public static SizeF MeasureString(NSAttributedString str, SizeF?availableSize = null)
 {
     SetContainerSize(availableSize);
     storage.SetString(str);
     return(layout.BoundingRectForGlyphRange(new NSRange(0, (int)str.Length), container).Size.ToEto());
 }
        private string DetectTappedUrl(UIGestureRecognizer tap, UILabel label, IEnumerable <LinkData> linkList)
        {
            // Creates instances of NSLayoutManager, NSTextContainer and NSTextStorage
            var layoutManager = new NSLayoutManager();
            var textContainer = new NSTextContainer();
            var textStorage   = new NSTextStorage();

            textStorage.SetString(label.AttributedText);

            // Configures layoutManager and textStorage
            layoutManager.AddTextContainer(textContainer);
            textStorage.AddLayoutManager(layoutManager);

            // Configures textContainer
            textContainer.LineFragmentPadding  = 0;
            textContainer.LineBreakMode        = label.LineBreakMode;
            textContainer.MaximumNumberOfLines = (nuint)label.Lines;
            var labelSize = label.Bounds.Size;

            textContainer.Size = labelSize;

            // Finds the tapped character location and compare it to the specified range
            var locationOfTouchInLabel = tap.LocationInView(label);
            var textBoundingBox        = layoutManager.GetUsedRectForTextContainer(textContainer);
            var textContainerOffset    = new CGPoint((labelSize.Width - textBoundingBox.Size.Width) * 0.0 - textBoundingBox.Location.X,
                                                     (labelSize.Height - textBoundingBox.Size.Height) * 0.0 - textBoundingBox.Location.Y);

            nfloat labelX;

            switch (Element.HorizontalTextAlignment)
            {
            case TextAlignment.End:
                labelX = locationOfTouchInLabel.X - (labelSize.Width - textBoundingBox.Size.Width);
                break;

            case TextAlignment.Center:
                labelX = locationOfTouchInLabel.X - (labelSize.Width - textBoundingBox.Size.Width) / 2;
                break;

            default:
                labelX = locationOfTouchInLabel.X;
                break;
            }
            var locationOfTouchInTextContainer = new CGPoint(labelX - textContainerOffset.X, locationOfTouchInLabel.Y - textContainerOffset.Y);

            nfloat partialFraction  = 0;
            var    indexOfCharacter = (nint)layoutManager.CharacterIndexForPoint(locationOfTouchInTextContainer, textContainer, ref partialFraction);

            nint scaledIndexOfCharacter = 0;

            // Problem is that method CharacterIndexForPoint always returns index based on UILabel font
            // ".SFUIText" which is the default Helvetica iOS font
            // HACK is to scale indexOfCharacter for 13% because NeoSans-Light is narrower font than ".SFUIText"
            if (label.Font.Name == "NeoSans-Light")
            {
                scaledIndexOfCharacter = (nint)(indexOfCharacter * 1.13);
            }

            // HelveticaNeue font family works perfect until character position in the string is more than 2000 chars
            // some uncosnsistent behaviour
            // if string has <b> tag than label.Font.Name from HelveticaNeue-Thin goes to HelveticaNeue-Bold
            if (label.Font.Name.StartsWith("HelveticaNeue", StringComparison.InvariantCulture))
            {
                scaledIndexOfCharacter = (nint)(indexOfCharacter * 1.02);
            }

            foreach (var link in linkList)
            {
                var rangeLength = link.Range.Length;
                var tolerance   = 0;
                if (label.Font.Name == "NeoSans-Light")
                {
                    rangeLength      = (nint)(rangeLength * 1.13);
                    tolerance        = 25;
                    indexOfCharacter = scaledIndexOfCharacter;
                }

                if (label.Font.Name.StartsWith("HelveticaNeue", StringComparison.InvariantCulture))
                {
                    if (link.Range.Location > 2000)
                    {
                        indexOfCharacter = scaledIndexOfCharacter;
                    }
                }

                // Xamarin version of NSLocationInRange?
                if ((indexOfCharacter >= (link.Range.Location - tolerance)) && (indexOfCharacter < (link.Range.Location + rangeLength + tolerance)))
                {
                    return(link.Url);
                }
            }
            return(null);
        }
Esempio n. 21
0
        public override void DrawRect(RectangleF dirtyRect)
        {
            var height = base.Bounds.Height;
            var calcValue = base.Bounds.Width * (Value * 0.01f);

            var context = NSGraphicsContext.CurrentContext.GraphicsPort;
            context.SetStrokeColor("#999999".ToCGColor());
            context.SetLineWidth (1.0F);

            context.StrokeRect(new RectangleF(0, 0, base.Bounds.Width, height));

            context.SetFillColor("#999999".ToCGColor());
            context.FillRect(new RectangleF(0, 0, base.Bounds.Width, height));

            context.SetFillColor(BackgroundColor.ToCGColor());
            context.FillRect(new RectangleF(0, 0, calcValue, height));

            var attrStr = "{0}".ToFormat(Label).CreateString("#ffffff".ToNSColor(), Font);

            var storage   = new NSTextStorage();
            storage.SetString(attrStr);

            var layout    = new NSLayoutManager();
            var container = new NSTextContainer();

            layout.AddTextContainer(container);
            storage.AddLayoutManager(layout);

            // Get size
            //			var size = layout.GetUsedRectForTextContainer (container).Size;
            //			var width = size.Width / 2.0f;
            var width = (base.Bounds.Width / 2.0f) - (TextOffset.X);

            storage.DrawString(new PointF(width, TextOffset.Y));
        }