public static RectangleF GetTextSize(CTFrame frame) { var minY = float.MaxValue; var maxY = float.MinValue; float width = 0; var lines = frame.GetLines(); var origins = new CGPoint[lines.Length]; frame.GetLineOrigins(new NSRange(0, 0), origins); for (var i = 0; i < lines.Length; i++) { var line = lines[i]; var lineWidth = (float)line.GetTypographicBounds(out var ascent, out var descent, out var leading); if (lineWidth > width) { width = lineWidth; } var origin = origins[i]; minY = (float)Math.Min(minY, origin.Y - ascent); maxY = (float)Math.Max(maxY, origin.Y + descent); lines[i].Dispose(); } return(new RectangleF(0f, minY, width, Math.Max(0, maxY - minY))); }
public override Size GetSize(object backend) { LayoutInfo li = (LayoutInfo)backend; using (CTFrame frame = CreateFrame(li)) { if (frame == null) { return(Size.Zero); } Size result = Size.Zero; CTLine [] lines = frame.GetLines(); float lineHeight = li.Font.Ascender - li.Font.Descender + li.Font.Leading; // try to approximate Pango's layout foreach (var line in lines) { result.Width = Math.Max(result.Width, line.GetTypographicBounds()); result.Height += lineHeight; // clean up after ourselves as we go line.Dispose(); } // CoreText throws away trailing line breaks.. if (li.Text.EndsWith("\n")) { result.Height += lineHeight; } result.Width = Math.Ceiling(result.Width); result.Height = Math.Ceiling(result.Height); return(result); } }
void TextChanged () { SetNeedsDisplay (); ClearPreviousLayoutInformation (); attributedString = new NSAttributedString (Text, attributes); framesetter = new CTFramesetter (attributedString); UIBezierPath path = UIBezierPath.FromRect (Bounds); frame = framesetter.GetFrame (new NSRange (0, 0), path.CGPath, null); }
void TextChanged() { SetNeedsDisplay(); ClearPreviousLayoutInformation(); attributedString = new NSAttributedString(Text, attributes); framesetter = new CTFramesetter(attributedString); UIBezierPath path = UIBezierPath.FromRect(Bounds); frame = framesetter.GetFrame(new NSRange(0, 0), path.CGPath, null); }
void ClearPreviousLayoutInformation () { if (framesetter != null) { framesetter.Dispose (); framesetter = null; } if (frame != null) { frame.Dispose (); frame = null; } }
public override Size GetSize(object backend) { LayoutInfo li = (LayoutInfo)backend; using (CTFrame frame = CreateFrame(li)) { if (frame == null) { return(Size.Zero); } Size result = Size.Zero; CTLine [] lines = frame.GetLines(); nfloat lineHeight = li.Font.Ascender - li.Font.Descender + li.Font.Leading; CTLine ellipsis = null; bool ellipsize = li.Width.HasValue && li.TextTrimming == TextTrimming.WordElipsis; if (ellipsize) { ellipsis = new CTLine(CreateAttributedString(li, "...")); } // try to approximate Pango's layout foreach (var line in lines) { var l = line; if (ellipsize) // we need to create a new CTLine here because the framesetter already truncated the text for the line { l = new CTLine(CreateAttributedString(li, li.Text.Substring((int)line.StringRange.Location))) .GetTruncatedLine(li.Width.Value, CTLineTruncation.End, ellipsis); line.Dispose(); } result.Width = Math.Max(result.Width, l.GetTypographicBounds()); result.Height += lineHeight; // clean up after ourselves as we go l.Dispose(); } // CoreText throws away trailing line breaks.. if (li.Text.EndsWith("\n")) { result.Height += lineHeight; } result.Width = Math.Ceiling(result.Width); result.Height = Math.Ceiling(result.Height); return(result); } }
void ClearPreviousLayoutInformation() { if (framesetter != null) { framesetter.Dispose(); framesetter = null; } if (frame != null) { frame.Dispose(); frame = null; } }
internal static void Draw(CGContext ctx, object layout, double x, double y) { LayoutInfo li = (LayoutInfo)layout; using (CTFrame frame = CreateFrame(li)) { if (frame == null) { return; } CTLine ellipsis = null; bool ellipsize = li.Width.HasValue && li.TextTrimming == TextTrimming.WordElipsis; if (ellipsize) { ellipsis = new CTLine(CreateAttributedString(li, "...")); } nfloat lineHeight = li.Font.Ascender - li.Font.Descender + li.Font.Leading; ctx.SaveState(); ctx.TextMatrix = CGAffineTransform.MakeScale(1f, -1f); ctx.TranslateCTM((float)x, (float)y + li.Font.Ascender); foreach (var line in frame.GetLines()) { ctx.TextPosition = CGPoint.Empty; // Determine final line var ln = line; if (ellipsize) { // we need to create a new CTLine here because the framesetter already truncated the text for the line ln = new CTLine(CreateAttributedString(li, li.Text.Substring((int)line.StringRange.Location))) .GetTruncatedLine(li.Width.Value, CTLineTruncation.End, ellipsis); line.Dispose(); } else if (li.Width.HasValue && li.TextAlignment != Alignment.Start) { var tx = li.Width.Value - GetLineWidth(ln); if (li.TextAlignment == Alignment.Center) { tx /= 2d; } ctx.TextPosition = new CGPoint((nfloat)tx, 0); } ln.Draw(ctx); ctx.TranslateCTM(0, lineHeight); ln.Dispose(); } ctx.RestoreState(); } }
void drawLabel(CGContext ctx, CGRect rect, nfloat yCoord, nfloat xCoord, UITextAlignment alignment, string label, bool flipContext = true, bool centerVertical = false) { // Draw light the sunrise and Sunset labels at the ends of the light box using (UIColor fontColor = UIColor.White, shadowColor = UIColor.Black.ColorWithAlpha(0.1f)) { var fontAttributes = new UIFontAttributes(new UIFontFeature(CTFontFeatureNumberSpacing.Selector.ProportionalNumbers)); using (var desc = UIFont.SystemFontOfSize(fontSize).FontDescriptor.CreateWithAttributes(fontAttributes)) { using (UIFont font = UIFont.FromDescriptor(desc, fontSize)) { // calculating the range of our attributed string var range = new NSRange(0, label.Length); // set justification for text block using (var alignStyle = new NSMutableParagraphStyle { Alignment = alignment }) { // add stylistic attributes to out attributed string var stringAttributes = new UIStringAttributes { ForegroundColor = fontColor, Font = font, ParagraphStyle = alignStyle }; var target = new CGSize(float.MaxValue, float.MaxValue); NSRange fit; using (NSMutableAttributedString attrString = new NSMutableAttributedString(label, stringAttributes)) { //creating a container for out attributed string using (CTFramesetter framesetter = new CTFramesetter(attrString)) { CGSize frameSize = framesetter.SuggestFrameSize(range, null, target, out fit); if (alignment == UITextAlignment.Center) { xCoord -= (frameSize.Width / 2); } if (alignment == UITextAlignment.Right) { xCoord -= frameSize.Width; } // subtract the frameSize so the flipped context behaves as expected yCoord -= frameSize.Height; if (centerVertical) { yCoord += (frameSize.Height / 2); } var textRect = new CGRect(xCoord, yCoord, frameSize.Width, frameSize.Height); using (CGPath path = new CGPath()) { path.AddRect(textRect); ctx.SetShadow(new CGSize(0.0f, 1.0f), 0.0f, shadowColor.CGColor); using (CTFrame frame = framesetter.GetFrame(range, path, null)) { if (flipContext) { ctx.SaveState(); ctx.TranslateCTM(0, rect.Height); ctx.ScaleCTM(1, -1); frame.Draw(ctx); ctx.RestoreState(); } else { frame.Draw(ctx); } } } } } } } } } }