Пример #1
0
        private Size LayoutTypography(Size size)
        {
            if (UseLayoutManager)
            {
                if (_textContainer == null)
                {
                    return(default(Size));
                }

                _textContainer.Size = size;

#if NET6_0_OR_GREATER
                return(_layoutManager.GetUsedRect
#else
                return _layoutManager.GetUsedRectForTextContainer
#endif

                           (_textContainer).Size);
            }
            else
            {
                if (_attributedString == null)
                {
                    return(default(Size));
                }

                return(_attributedString.GetBoundingRect(size, NSStringDrawingOptions.UsesLineFragmentOrigin, null).Size);
            }
        }
Пример #2
0
        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);
        }
Пример #4
0
        private Size LayoutTypography(Size size)
        {
            _textContainer.Size = size;

            // Required for GetUsedRectForTextContainer to return a value.
            _layoutManager.GetGlyphRange(_textContainer);

            return(_layoutManager.GetUsedRectForTextContainer(_textContainer).Size);
        }
Пример #5
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);
        }
Пример #6
0
        nfloat HeightWrappedToViewWidth(NSTextView textView, float width)
        {
            NSLayoutManager layoutManager = textView.LayoutManager;
            NSTextContainer container     = textView.TextContainer;

            layoutManager.GetGlyphRange(container);              //force layout
            nfloat height = layoutManager.GetUsedRectForTextContainer(container).Height;

            return(height);
        }
Пример #7
0
 private Size LayoutTypography(Size size)
 {
     if (UseLayoutManager)
     {
         _textContainer.Size = size;
         return(_layoutManager.GetUsedRectForTextContainer(_textContainer).Size);
     }
     else
     {
         return(_attributedString.GetBoundingRect(size, NSStringDrawingOptions.UsesLineFragmentOrigin, null).Size);
     }
 }
Пример #8
0
 public CGSize GetSize()
 {
     using (var TextLayout = new NSLayoutManager())
     {
         TextLayout.AddTextContainer(TextContainer);
         TextStorage.AddLayoutManager(TextLayout);
         TextLayout.GlyphRangeForBoundingRect(new CGRect(CGPoint.Empty, TextContainer.Size), TextContainer);
         var s = TextLayout.GetUsedRectForTextContainer(TextContainer);
         TextStorage.RemoveLayoutManager(TextLayout);
         TextLayout.RemoveTextContainer(0);
         return(s.Size);
     }
 }
Пример #9
0
        nfloat HeightWrappedToWidth(float width)
        {
            nfloat          height        = 0;
            NSTextStorage   storage       = new NSTextStorage();
            NSLayoutManager layoutManager = new NSLayoutManager();
            CGSize          size          = new CGSize(width, 100);
            NSTextContainer container     = new NSTextContainer(size);

            layoutManager.AddTextContainer(container);
            storage.AddLayoutManager(layoutManager);
            layoutManager.GetGlyphRange(container);              //force layout
            height = layoutManager.GetUsedRectForTextContainer(container).Height;

            return(height);
        }
Пример #10
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);
        }
        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);
        }
Пример #12
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);
        }
Пример #13
0
        private Size LayoutTypography(Size size)
        {
            if (UseLayoutManager)
            {
                if (_textContainer == null)
                {
                    return(default(Size));
                }

                _textContainer.Size = size;
                // Required for GetUsedRectForTextContainer to return a value.
                _layoutManager.GetGlyphRange(_textContainer);
                return(_layoutManager.GetUsedRectForTextContainer(_textContainer).Size);
            }
            else
            {
                if (_attributedString == null)
                {
                    return(default(Size));
                }

                return(_attributedString.BoundingRectWithSize(size, NSStringDrawingOptions.UsesLineFragmentOrigin, null).Size);
            }
        }
Пример #14
0
        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);
        }
Пример #15
0
 private Size LayoutTypography(Size size)
 {
     _textContainer.Size = size;
     return(_layoutManager.GetUsedRectForTextContainer(_textContainer).Size);
 }
        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);
        }