Example #1
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);
        }
Example #2
0
        protected override void OnElementChanged(ElementChangedEventArgs <MyLabel> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null)
            {
                if (Control == null)
                {
                    var uiLabel = new UILabel
                    {
                        UserInteractionEnabled = true,
                        LineBreakMode          = UILineBreakMode.WordWrap,
                        Lines = 0,
                        Text  = "عندما يريد العالم أن ‪يتكلّم ‬ ، فهو يتحدّث بلغة يونيكود. تسجّل الآن لحضور المؤتمر الدولي العاشر ليونيكود (Unicode Conference)، الذي سيعقد في 10-12 آذار 1997 بمدينة مَايِنْتْس، ألمانيا. و سيجمع المؤتمر بين خبراء من كافة قطاعات الصناعة على الشبكة العالمية انترنيت ويونيكود، حيث ستتم، على الصعيدين الدولي والمحلي على حد سواء مناقشة سبل استخدام يونكود في النظم القائمة وفيما يخص التطبيقات الحاسوبية، الخطوط، تصميم النصوص والحوسبة متعددة اللغات...TapMe"
                    };

                    var uiTapGestureRecognizer = new UITapGestureRecognizer();
                    uiTapGestureRecognizer.AddTarget(() =>
                    {
                        var label      = uiLabel;
                        var recognizer = uiTapGestureRecognizer;
                        var range      = new NSRange(uiLabel.Text.Length - "TapMe".Length, "TapMe".Length);

                        using (var ts = new NSTextStorage())
                        {
                            var lm = new NSLayoutManager();
                            var tc = new NSTextContainer(new CGSize(label.Frame.Width, double.MaxValue));

                            lm.AddTextContainer(tc);
                            ts.Append(label.AttributedText);
                            ts.AddLayoutManager(lm);

                            tc.LineFragmentPadding  = (float)0.0;
                            tc.LineBreakMode        = label.LineBreakMode;
                            tc.MaximumNumberOfLines = (uint)label.Lines;
                            tc.Size = label.Bounds.Size;

                            var index         = lm.GetCharacterIndex(recognizer.LocationOfTouch(0, label), tc);
                            var isWithinRange = (nint)index >= range.Location && (nint)index < range.Location + range.Length;

                            App.Current.MainPage.DisplayAlert("Alert", "Character count: " + label.Text.Length + "\nRange location: " + range.Location + "\nRange length:" + range.Length + "\nCharacter index: " + index + "\nIs within range: " + isWithinRange, "Dismiss");
                        }
                    });
                    uiLabel.AddGestureRecognizer(uiTapGestureRecognizer);

                    SetNativeControl(uiLabel);
                }
            }
        }
Example #3
0
        private int GetCharacterIndexAtPoint(Point point)
        {
            if (!_drawRect.Contains(point))
            {
                return(-1);
            }

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

#if NET6_0_OR_GREATER
            var characterIndex = (int)_layoutManager.GetCharacterIndex
                                     (pointInTextContainer, _layoutManager.TextContainers.FirstOrDefault(), out partialFraction);
#else
#pragma warning disable CS0618 // Type or member is obsolete (For VS2017 compatibility)
            var characterIndex = (int)_layoutManager.CharacterIndexForPoint
                                     (pointInTextContainer, _layoutManager.TextContainers.FirstOrDefault(), ref partialFraction);
#pragma warning restore CS0618 // Type or member is obsolete
#endif

            return(characterIndex);
        }
Example #4
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;
            CGSize labelSize = label.Bounds.Size;

            textContainer.Size = labelSize;

            // Finds the tapped character location and compare it to the specified range
            CGPoint locationOfTouchInLabel = tap.LocationInView(label);
            CGRect  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);

            var indexOfCharacter = (nint)layoutManager.GetCharacterIndex(locationOfTouchInTextContainer, textContainer);

            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 (LinkData link in linkList)
            {
                nint 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);
        }