在 xamarin ios 中沿圆形路径绘制文本

Posted

技术标签:

【中文标题】在 xamarin ios 中沿圆形路径绘制文本【英文标题】:Draw text along circular path in xamarin ios 【发布时间】:2017-10-17 14:03:51 【问题描述】:

我在以下链接中找到了答案: Draw text along circular path in Swift for ios

这对我来说似乎很好。现在,我只是想在 xamarin ios 中转换相同的代码,但还没有成功。

 public class CircularText : UIView

    public override void Draw(CoreGraphics.CGRect rect)
    
        base.Draw(rect);
        this.BackgroundColor = UIColor.Clear;
        var context = UIGraphics.GetCurrentContext();
        var size = this.Bounds.Size;

        context.TranslateCTM(size.Width / 2, size.Height / 2);
        context.ScaleCTM(1, -1);


        CentreArcPerpendicular(str: "Hello round world", context: context, radius: 100, angle: 0, color: UIColor.Red, font: UIFont.SystemFontOfSize(16), clockwise: true);
        CentreArcPerpendicular(str: "Anticlockwise", context: context, radius: 100, angle: (System.nfloat)(-Math.PI / 2), color: UIColor.Red, font: UIFont.SystemFontOfSize(16), clockwise: false);
        centre(str: "Hello flat world", context: context, radius: 0, angle: 0, color: UIColor.Yellow, font: UIFont.SystemFontOfSize(16), slantAngle: (System.nfloat)(Math.PI / 4));
    

    void CentreArcPerpendicular(String str, CGContext context, nfloat radius, nfloat angle, UIColor color, UIFont font, bool clockwise)
    
        var l = str.Length;
        char[] characters = str.ToCharArray();
        nfloat[] arcs = new nfloat[l];
        nfloat totalArc = 0;

        for (int i = 0; i < l; i++)
        
            arcs[i] = chordToArc(1, radius);  
        

        var direction = clockwise ? -1 : 1;
        var slantCorrection = clockwise ? -Math.PI / 2 : Math.PI;

        var thetaI = angle - direction * totalArc / 2;


        for (int i = 0; i < l; i++)
        
            thetaI += direction * arcs[i] / 2;
            centre(str: characters[i].ToString(), context: context, radius: radius, angle: angle, color: color, font: font, slantAngle: (System.nfloat)(angle + slantCorrection));
            thetaI += direction * arcs[i] / 2;
        
    

    nfloat chordToArc(nfloat chord, nfloat radius)
    
        return (nfloat)(2 * Math.Asin(chord / (2 * radius)));
    

    void centre(String str, CGContext context, nfloat radius, nfloat angle, UIColor color, UIFont font, nfloat slantAngle)
    
        //var attributes = [NSForegroundColorAttributeName: color,
        //NSFontAttributeName: font]

        context.SaveState();
        //    // Undo the inversion of the Y-axis (or the text goes backwards!)
        context.ScaleCTM(1, -1);
        // Move the origin to the centre of the text (negating the y-axis manually)
        context.TranslateCTM((System.nfloat)(radius * Math.Cos(angle)), (System.nfloat)(-(radius * Math.Sin(angle))));
        // Rotate the coordinate system
        context.RotateCTM(-slantAngle);
        // Calculate the width of the text
        var offset = str.Length;
        // Move the origin by half the size of the text

        //CGContextTranslateCTM(context, -offset.width / 2, -offset.height / 2)
        context.TranslateCTM(-20 / 2, 20 / 2); // Move the origin to the centre of the text (negating the y-axis manually)
        // Draw the text
        str.DrawString(new CGPoint(x: 0, y: 0), font);
        // Restore the context
        context.RestoreState();
    

一些 cmets 显示原始行,它可能没有正确翻译...它对我来说只显示黑色视图

【问题讨论】:

【参考方案1】:

将swift代码转换为C#时有几个错误,我在下面的代码sn-p中更正了它们。它是黑色的原因是您没有为文本设置颜色。您可以改用NSString.DrawString 来实现。

应该是这样的:

        public override void Draw(CoreGraphics.CGRect rect)
        
            base.Draw(rect);
            this.BackgroundColor = UIColor.Clear;
            var context = UIGraphics.GetCurrentContext();
            var size = this.Bounds.Size;

            context.TranslateCTM(size.Width / 2, size.Height / 2);
            context.ScaleCTM(1, -1);


            CentreArcPerpendicular(str: "Hello round world", context: context, radius: 100, angle: 0, color: UIColor.Red, font: UIFont.SystemFontOfSize(16), clockwise: true);
            CentreArcPerpendicular(str: "Anticlockwise", context: context, radius: 100, angle: (System.nfloat)(-Math.PI / 2), color: UIColor.Red, font: UIFont.SystemFontOfSize(16), clockwise: false);
            centre(str: "Hello flat world", context: context, radius: 0, angle: 0, color: UIColor.Yellow, font: UIFont.SystemFontOfSize(16), slantAngle: (System.nfloat)(Math.PI / 4));
        

        void CentreArcPerpendicular(String str, CGContext context, nfloat radius, nfloat angle, UIColor color, UIFont font, bool clockwise)
        
            var l = str.Length;
            char[] characters = str.ToCharArray();
            nfloat[] arcs = new nfloat[l];
            nfloat totalArc = 0;

            for (int i = 0; i < l; i++)
            

                //Get the Size of the Char(Transfer to string to get the width)
                NSString s = new NSString(Char.ToString(characters[i]));
                CGSize size = s.GetSizeUsingAttributes(new UIStringAttributes(new NSDictionary(UIStringAttributeKey.Font, font)));

                arcs[i] = chordToArc(size.Width, radius);

                totalArc += arcs[i];

            

            var direction = clockwise ? -1 : 1;
            var slantCorrection = clockwise ? -Math.PI / 2 : Math.PI / 2 ; //You lose the /2

            var thetaI = angle - direction * totalArc / 2;


            for (int i = 0; i < l; i++)
            
                thetaI += direction * arcs[i] / 2;
                centre(str: characters[i].ToString(), context: context, radius: radius, angle: thetaI, color: color, font: font, slantAngle: (System.nfloat)(thetaI + slantCorrection)); // USe thetaI not angle !
                thetaI += direction * arcs[i] / 2;
            
        

        nfloat chordToArc(nfloat chord, nfloat radius)
        
            return (nfloat)(2 * Math.Asin(chord / (2 * radius)));
        

        void centre(String str, CGContext context, nfloat radius, nfloat angle, UIColor color, UIFont font, nfloat slantAngle)
        
            // Set the text attributes
            UIStringAttributes attribute = new UIStringAttributes()
            
                Font = font,
                ForegroundColor = color
            ;

            NSString s = new NSString(str);

            // Save the context
            context.SaveState();
            // Undo the inversion of the Y-axis (or the text goes backwards!)
            context.ScaleCTM(1, -1);
            // Move the origin to the centre of the text (negating the y-axis manually)
            context.TranslateCTM((System.nfloat)(radius * Math.Cos(angle)), (System.nfloat)(-(radius * Math.Sin(angle))));
            // Rotate the coordinate system
            context.RotateCTM(-slantAngle);
            // Calculate the width of the text
            var offset = s.GetSizeUsingAttributes(attribute);
            // Move the origin by half the size of the text
            context.TranslateCTM(-offset.Width / 2, -offset.Height / 2); // Move the origin to the centre of the text (negating the y-axis manually)

            // Draw the text
            s.DrawString(new CGPoint(0, 0), attribute);//use NSString.DrawString, then it can add attribute parameter.
            // Restore the context
            context.RestoreState();
        

它可以像这样正常工作:

【讨论】:

以上是关于在 xamarin ios 中沿圆形路径绘制文本的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SwiftUI 沿圆形路径绘制文本

iOS开发Quzrtz2D 十:圆形图片的绘制以及加边框圆形图片的绘制

避免在ggplot中沿轴剪裁点

如何在 Xamarin.iOS 中绘制圆角矩形?

如何在 iOS Swift4 中创建这个圆形?

xamarin.ios 实现圆形进度条