Reputation: 13972
I would like to draw text at a given point (x, y) in the Draw
method of a custom View
.
I have followed this sample from the Xamarin site.
This is the View I created:
public class MyView : UIView
{
public override void Draw(CGRect rect)
{
using (var context = UIGraphics.GetCurrentContext())
{
DrawText(context, "hello", 20, new CGPoint(0, 0));
DrawText(context, "how are you", 20, new CGPoint(0, 40));
}
}
private void DrawText(CGContext context, string text, int textHeight, CGPoint point)
{
var x = point.X;
var y = point.Y + textHeight;
context.TranslateCTM(x, y);
context.ScaleCTM(1, -1);
context.SetFillColor(UIColor.Red.CGColor);
var attributedString = new NSAttributedString(text,
new CTStringAttributes
{
ForegroundColorFromContext = true,
Font = new CTFont("Arial", 16)
});
using (var textLine = new CTLine(attributedString))
{
textLine.Draw(context);
}
}
}
The problem is that the DrawText
method only works OK once. The first time you call it the text is drawn, but it doesn't work on successive calls (it draws nothing, or what it draws isn't visible).
What am I doing wrong?
Upvotes: 2
Views: 2126
Reputation: 13972
I took @SushiHangover's code and modified it to work for me, since their version (1st in his post) had some problems (read notice below):
public void DrawText(FormattedText formattedText, Point point)
{
context.SaveState();
context.ScaleCTM(1, -1);
context.SetFillColor(formattedText.Brush.Color.ToiOS());
var sizeOfText = formattedText.DesiredSize;
var ctFont = new CTFont(formattedText.FontName, formattedText.FontSize);
var attributedString = new NSAttributedString(formattedText.Text,
new CTStringAttributes
{
ForegroundColor = formattedText.Brush.Color.ToiOS(),
Font = ctFont
});
context.TextPosition = new CGPoint(point.X, -(point.Y + sizeOfText.Height - ctFont.DescentMetric));
using (var textLine = new CTLine(attributedString))
{
textLine.Draw(context);
}
context.RestoreState();
}
Keep into account that FormattedText
and Point
are custom classes I made to encapsulate the text to be drawn and the point where to draw it. Their properties are as simple as you see :)
IMPORTANT: The modifications to @SushiHangover's version are there to
Avoid side effects (if I drew a Rectangle after calling the DrawText method, the coordinates were messed up, for instance). It also had a problem with the x coordinate:
context.TranslateCTM(-x, -(y + textHeight))
should be
context.TranslateCTM(x, -(y + textHeight))
Upvotes: 1
Reputation: 74094
So there are two basic things that are wrong with your code.
ScaleCTM
and a TranslateCTM
each time you call DrawText
CTLine.Draw
, the "cursor" is moved to the end of that text.So, call ScaleCTM
to flipped the whole thing so the text gets draw left2right, then call DrawText
and translate to where you want to paint the text and then translate back to where you started so the next time you are at the same point.
public override void Draw(CGRect rect)
{
var context = UIGraphics.GetCurrentContext();
context.ScaleCTM(1, -1); // you flipped the context, now you must use negative Y values to draw "into" the view
var textHeight = new CTFont("Arial", 16).CapHeightMetric; // lets use the actaul height of the font captials.
DrawText(context, "Hello", textHeight, 0, 0);
DrawText(context, "How are you?", textHeight, 0, 20);
DrawText(context, "Sincerely,", textHeight, 0, 40);
DrawText(context, "StackOverflow,", textHeight, 0, 60);
}
void DrawText(CGContext context, string text, nfloat textHeight, nfloat x, nfloat y)
{
context.TranslateCTM(-x, -(y + textHeight));
context.SetFillColor(UIColor.Red.CGColor);
var attributedString = new NSAttributedString(text,
new CTStringAttributes
{
ForegroundColorFromContext = true,
Font = new CTFont("Arial", 16)
});
CGRect sizeOfText;
using (var textLine = new CTLine(attributedString))
{
textLine.Draw(context);
sizeOfText = textLine.GetBounds(CTLineBoundsOptions.UseOpticalBounds);
}
// Reset the origin back to where is was
context.TranslateCTM(x - sizeOfText.Width, y + sizeOfText.Height);
}
var context = UIGraphics.GetCurrentContext();
CGRect textRect = new CGRect(0.0f, 0.0f, 200.0f, 100.0f);
{
var textContent = "Hello\nHow are you?\nSincerely,\nStackOverflow";
UIColor.Red.SetFill();
var textStyle = new NSMutableParagraphStyle ();
textStyle.Alignment = UITextAlignment.Left;
var textFontAttributes = new UIStringAttributes () {Font = UIFont.FromName("ArialMT", 16.0f), ForegroundColor = UIColor.Red, ParagraphStyle = textStyle};
var textTextHeight = new NSString(textContent).GetBoundingRect(new CGSize(textRect.Width, nfloat.MaxValue), NSStringDrawingOptions.UsesLineFragmentOrigin, textFontAttributes, null).Height;
context.SaveState();
context.ClipToRect(textRect);
new NSString(textContent).DrawString(new CGRect(textRect.GetMinX(), textRect.GetMinY() + (textRect.Height - textTextHeight) / 2.0f, textRect.Width, textTextHeight), UIFont.FromName("ArialMT", 16.0f), UILineBreakMode.WordWrap, UITextAlignment.Left);
context.RestoreState();
}
Upvotes: 2