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); }
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);
public override void ViewDidLoad() { base.ViewDidLoad(); textStorage = new InteractiveTextColoringTextStorage(); CGRect newTextViewRect = View.Bounds; newTextViewRect.X += 8; newTextViewRect.Width -= 16; var layoutManager = new NSLayoutManager(); var container = new NSTextContainer(new CGSize(newTextViewRect.Size.Width, float.MaxValue)); container.WidthTracksTextView = true; layoutManager.AddTextContainer(container); textStorage.AddLayoutManager(layoutManager); var newTextView = new UITextView(newTextViewRect, container); newTextView.AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth; newTextView.ScrollEnabled = true; newTextView.KeyboardDismissMode = UIScrollViewKeyboardDismissMode.OnDrag; View.Add(newTextView); var tokens = new Dictionary <string, NSDictionary> (); tokens.Add("Alice", new NSDictionary(UIStringAttributeKey.ForegroundColor, UIColor.Red)); tokens.Add("Rabbit", new NSDictionary(UIStringAttributeKey.ForegroundColor, UIColor.Orange)); tokens.Add("DefaultTokenName", new NSDictionary(UIStringAttributeKey.ForegroundColor, UIColor.Black)); textStorage.Tokens = tokens; SetText(); }
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) ); } }
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); }
public override void ViewDidLoad () { base.ViewDidLoad (); textStorage = new InteractiveTextColoringTextStorage (); CGRect newTextViewRect = View.Bounds; newTextViewRect.X += 8; newTextViewRect.Width -= 16; var layoutManager = new NSLayoutManager (); var container = new NSTextContainer (new CGSize (newTextViewRect.Size.Width, float.MaxValue)); container.WidthTracksTextView = true; layoutManager.AddTextContainer (container); textStorage.AddLayoutManager (layoutManager); var newTextView = new UITextView (newTextViewRect, container); newTextView.AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth; newTextView.ScrollEnabled = true; newTextView.KeyboardDismissMode = UIScrollViewKeyboardDismissMode.OnDrag; View.Add (newTextView); var tokens = new Dictionary<string, NSDictionary> (); tokens.Add ("Alice", new NSDictionary (UIStringAttributeKey.ForegroundColor, UIColor.Red)); tokens.Add ("Rabbit", new NSDictionary (UIStringAttributeKey.ForegroundColor, UIColor.Orange)); tokens.Add ("DefaultTokenName", new NSDictionary (UIStringAttributeKey.ForegroundColor, UIColor.Black)); textStorage.Tokens = tokens; SetText (); }
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); }
// 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); }
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 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); } }
public CGPoint GetCoordinateFromIndex(int index) { using (var TextLayout = new NSLayoutManager()) { TextLayout.AddTextContainer(TextContainer); TextStorage.AddLayoutManager(TextLayout); TextLayout.GlyphRangeForBoundingRect(new CGRect(CGPoint.Empty, TextContainer.Size), TextContainer); var glyphIndex = TextLayout.GlyphIndexForCharacterAtIndex(index); var p = TextLayout.LocationForGlyphAtIndex((nint)glyphIndex); TextStorage.RemoveLayoutManager(TextLayout); TextLayout.RemoveTextContainer(0); return(p); } }
public nuint GetIndexFromCoordinates(double x, double y) { using (var TextLayout = new NSLayoutManager()) { TextLayout.AddTextContainer(TextContainer); TextStorage.AddLayoutManager(TextLayout); TextLayout.GlyphRangeForBoundingRect(new CGRect(CGPoint.Empty, TextContainer.Size), TextContainer); nfloat fraction = 0; var index = TextLayout.CharacterIndexForPoint(new CGPoint(x, y), TextContainer, ref fraction); TextStorage.RemoveLayoutManager(TextLayout); TextLayout.RemoveTextContainer(0); return(index); } }
public void LowLevelGetAttributesOverrideTest() { using var storage = new MyTextStorage("Hello World"); using var container = new NSTextContainer { Size = new CGSize(100, float.MaxValue), WidthTracksTextView = true }; using var layoutManager = new NSLayoutManager(); layoutManager.AddTextContainer(container); storage.AddLayoutManager(layoutManager); layoutManager.EnsureLayoutForCharacterRange(new NSRange(0, 1)); Assert.That(storage.LowLevelGetAttributes_Called, Is.GreaterThan(0), "LowLevelGetAttributes #called"); Assert.That(storage.LowLevelValue_Called, Is.GreaterThan(0), "LowLevelValue #called"); }
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); } } }
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); }
public void CreateManager() { // This sets up the global context so our drawing doesn't produce error messages NSBitmapImageRep bitmap = new NSBitmapImageRep(IntPtr.Zero, 1000, 1000, 16, 4, true, false, NSColorSpace.DeviceRGB, 0, 0); NSGraphicsContext.CurrentContext = NSGraphicsContext.FromBitmap(bitmap); NSTextStorage storage = new NSTextStorage("Hello World"); NSTextContainer container = new NSTextContainer(); manager = new NSLayoutManager(); manager.AddTextContainer(container); storage.AddLayoutManager(manager); }
static FontExtensions() { storage = new NSTextStorage(); layout = new NSLayoutManager { UsesFontLeading = true }; #if OSX layout.BackgroundLayoutEnabled = false; #endif container = new NSTextContainer { LineFragmentPadding = 0f }; layout.UsesFontLeading = true; layout.AddTextContainer(container); storage.AddLayoutManager(layout); }
public void Draw(CGContext ctx, CGColor foregroundColor, double x, double y) { bool tempForegroundSet = false; // if no color attribute is set for the whole string, // NSLayoutManager will use the default control foreground color. // To override the default color we need to apply the current CGContext stroke color // before all other attributes are set, otherwise it will remove all other foreground colors. if (foregroundColor != null && !Attributes.Any(a => a is ColorTextAttribute && a.StartIndex == 0 && a.Count == Text.Length)) { // FIXME: we need to find a better way to accomplish this without the need to reset all attributes. ResetAttributes(NSColor.FromCGColor(foregroundColor)); tempForegroundSet = true; } ctx.SaveState(); NSGraphicsContext.GlobalSaveGraphicsState(); var nsContext = NSGraphicsContext.FromCGContext(ctx, true); NSGraphicsContext.CurrentContext = nsContext; using (var TextLayout = new NSLayoutManager()) { TextLayout.AddTextContainer(TextContainer); TextStorage.AddLayoutManager(TextLayout); TextLayout.DrawBackgroundForGlyphRange(new NSRange(0, Text.Length), new CGPoint(x, y)); TextLayout.DrawGlyphsForGlyphRange(new NSRange(0, Text.Length), new CGPoint(x, y)); TextStorage.RemoveLayoutManager(TextLayout); TextLayout.RemoveTextContainer(0); } // reset foreground color change if (tempForegroundSet) { ResetAttributes(); } NSGraphicsContext.GlobalRestoreGraphicsState(); ctx.RestoreState(); }
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 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); }
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)); }
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); } }
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 void SetStyle() { if (ExtendedLabel.Children != null && ExtendedLabel.Children.Count > 0) { NSTextStorage attributedString = new NSTextStorage(); _styledTextPartList = new List <KeyValuePair <int, StyledTextPart> >(); ExtendedLabel.Children.ToList().ForEach(styledTextPart => { _styledTextPartList.Add(new KeyValuePair <int, StyledTextPart>(Convert.ToInt32(attributedString.Length), styledTextPart)); attributedString.Append(styledTextPart.CustomFont.BuildAttributedString(styledTextPart.Text, this.Control.TextAlignment)); }); Control.AttributedText = attributedString; Control.UserInteractionEnabled = true; var tapGestureRecognizer = new UITapGestureRecognizer(); tapGestureRecognizer.AddTarget(() => LabelTapped(tapGestureRecognizer)); Control.AddGestureRecognizer(tapGestureRecognizer); //if (!ExtendedLabel.TextShouldWrap) //{ // Control.Lines = 1; //} _layoutManager = new NSLayoutManager(); _layoutManager.AddTextContainer(_textContainer); attributedString.AddLayoutManager(_layoutManager); return; } if (ExtendedLabel.Text != null) { var attributedString = ExtendedLabel.CustomFont.BuildAttributedString(ExtendedLabel.Text, this.Control.TextAlignment); Control.AttributedText = attributedString; } }
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); }
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; } }
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)); }
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); }
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); }