【问题标题】:How to draw text in Xamarin iOS?如何在 Xamarin iOS 中绘制文本?
【发布时间】:2019-07-26 02:44:00
【问题描述】:

我想在自定义 ViewDraw 方法中的给定点 (x, y) 处绘制文本。

我已从 Xamarin 网站关注 this sample

这是我创建的视图:

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);
        }
    }
}

问题在于DrawText 方法只能正常工作一次。第一次调用它时,会绘制文本,但它在连续调用时不起作用(它什么也不绘制,或者它绘制的内容不可见)。

我做错了什么?

【问题讨论】:

  • 嗯 - 你需要类似 setNeedsLayout 或类似的东西吗?只是一个疯狂的猜测!
  • 在iOS中,基本上,只再次使用drawRect例程,当setNeedsLayout ....
  • 应该需要调用SetNeedsLayout。我只想在相同的上下文中绘制另一个文本。

标签: c# ios .net xamarin xamarin.ios


【解决方案1】:

因此,您的代码有两个基本问题。

  • 每次调用DrawText 时,您都在执行ScaleCTMTranslateCTM
  • 您没有考虑到当您CTLine.Draw 时,“光标”会移动到该文本的末尾。

所以,调用ScaleCTM 翻转整个内容,使文本从左到右绘制,然后调用DrawText 并翻译到您要绘制文本的位置,然后翻译回到您要绘制文本的位置开始,所以下次你在同一点时。

示例绘制覆盖:

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); 
}

结果:

使用 NSMutableParagraphStyle 和 NSString.DrawString

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();
}

【讨论】:

  • 请检查我的答案!我已将您的代码作为基础并进行了修改以使用我的代码。 FormattedText是封装了要写入的文本属性的类型,Point是我自定义的Point结构。
【解决方案2】:

我采用了@SushiHangover 的代码并对其进行了修改以适合我,因为他们的版本(他的帖子中的第一个)存在一些问题(请阅读下面的通知):

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();
}

请注意FormattedTextPoint 是我为封装要绘制的文本和绘制它的点而创建的自定义类。它们的属性就像你看到的一样简单:)

重要提示:对@SushiHangover 版本的修改是为了

避免副作用(例如,如果我在调用 DrawText 方法后绘制了一个 Rectangle,那么坐标就会混乱)。 x坐标也有问题:

context.TranslateCTM(-x, -(y + textHeight)) 

应该是

context.TranslateCTM(x, -(y + textHeight)) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-28
    • 2023-03-13
    • 2012-07-21
    • 2020-01-30
    • 2014-02-11
    • 2011-10-28
    • 2021-05-11
    • 1970-01-01
    相关资源
    最近更新 更多