【问题标题】:Xamarin iOS CGPath draw polygon with curved/rounded cornersXamarin iOS CGPath 绘制带有弯曲/圆角的多边形
【发布时间】:2016-06-10 17:08:08
【问题描述】:

我正在尝试创建一个在自定义UIView 子类中绘制多边形的类。我有它的工作,但现在我想通过四舍五入来平滑角落,我不知道该怎么做。这是我目前所拥有的:

public class MyView : UIView
{
    private List<CGPoint> points;

    public MyView(CGRect frame, List<CGPoint> points) : base (frame)
    {
        this.points = points;
    }

    public override Draw (CGRect rect)
    {
        CGContext context = UIGraphics.GetCurrentContext();

        context.SetLineWidth(2);
        UIColor.Black.SetStroke();
        UIColor.Green.SetFill();

        CGPath path = new CGPath();
        path.AddLines(points.ToArray());
        path.CloseSubpath();

        context.AddPath(path);
        context.Clip();

        using (CGColorSpace rgb = CGColorSpace.CreateDeviceRGB())
        {
            CGGradient gradient = new CGGradient (rgb, new CGColor[]
            {
                new CGColor(0, 1, 0),
                new CGColor(0, 0.5f, 0),
                new CGColor(0, 1, 0),
                new CGColor(0, 0.5f, 0)
            });

            context.DrawLinearGradient(gradient,
                new CGPoint (path.BoundingBox.Left, path.BoundingBox.Top), 
                new CGPoint (path.BoundingBox.Right, path.BoundingBox.Bottom), 
                CGGradientDrawingOptions.DrawsBeforeStartLocation);
        }
    }
}

根据我的分数,我明白了:

我尝试过使用path.AddCurveToPointpath.AddArc,但我似乎无法让它们按照我想要的方式工作。任何帮助将不胜感激。

编辑

我玩过path.AddCurveToPoint,现在看起来像这样:

它一开始是正确的,但随后就完全发疯了。不知道我在这里做错了什么。这是我更新的Draw 覆盖:

public override Draw (CGRect rect)
{
    CGContext context = UIGraphics.GetCurrentContext();

    context.SetLineWidth(2);
    UIColor.Black.SetStroke();
    UIColor.Green.SetFill();

    CGPath path = new CGPath();
    path.AddLines(points.ToArray());
    path.CloseSubpath();
    // updated section
    int count = points.Count;

    for (int x = 1; x < count; x++)
    {
        var p = points[x];
        if (x != 0)
        {
            var prev = points[x - 1];
            if (prev.Y != p.Y)
            {
                if (prev.Y > p.Y)
                {
                    path.AddCurveToPoint(prev, new CGPoint(p.X - prev.X, p.Y), p);
                }
                else
                {
                    //???
                }
            }
        }
    }
    // end updated section
    context.AddPath(path);
    context.Clip();

    using (CGColorSpace rgb = CGColorSpace.CreateDeviceRGB())
    {
        CGGradient gradient = new CGGradient (rgb, new CGColor[]
        {
            new CGColor(0, 1, 0),
            new CGColor(0, 0.5f, 0),
            new CGColor(0, 1, 0),
            new CGColor(0, 0.5f, 0)
        });

        context.DrawLinearGradient(gradient,
            new CGPoint (path.BoundingBox.Left, path.BoundingBox.Top), 
            new CGPoint (path.BoundingBox.Right, path.BoundingBox.Bottom), 
            CGGradientDrawingOptions.DrawsBeforeStartLocation);
    }
}

【问题讨论】:

    标签: c# ios xamarin polygon cgpath


    【解决方案1】:

    更新:

    通过您的更新,我现在看到了您的问题。您正在尝试将您的点列表用作 Bézier 控制点和多边形角的绘制点,这将不起作用。

    “最简单”的方式是使用现有的点列表作为控制点,并在每个控制点之间创建中间节点,并为每个段添加四边形曲线。

    注意:更难的方法是使用您的点列表作为节点,并为每个贝塞尔曲线段创建控制点。我不会在这里详细介绍,但许多图表系统使用此 article 作为参考,getControlPoints 的返回值将用作方法 AddCurveToPoint 的控制点。

    简单的例子:

    var color = UIColor.Red;
    var color2 = UIColor.White;
    
    var points = new List<CGPoint>() { 
        new CGPoint(136.49f, 134.6f),
        new CGPoint(197.04f, 20.0f),
        new CGPoint(257.59f, 20.0f),
        new CGPoint(303.0f, 134.6f),
        new CGPoint(303.0f, 252.0f),
        new CGPoint(28.0f, 252.0f),
        new CGPoint(28.0f, 134.6f),
        new CGPoint(136.49f, 134.6f)
    };
    
    UIBezierPath polygonPath = new UIBezierPath();
    polygonPath.MoveTo(points[0]);
    polygonPath.AddLineTo(points[1]);
    polygonPath.AddLineTo(points[2]);
    polygonPath.AddLineTo(points[3]);
    polygonPath.AddLineTo(points[4]);
    polygonPath.AddLineTo(points[5]);
    polygonPath.AddLineTo(points[6]);
    polygonPath.ClosePath();
    polygonPath.Fill();
    color2.SetStroke();
    polygonPath.LineWidth = 10.0f;
    polygonPath.Stroke();
    
    UIBezierPath smoothedPath = new UIBezierPath();
    var m0 = MidPoint(points[0], points[1]);
    smoothedPath.MoveTo(m0);
    smoothedPath.AddQuadCurveToPoint(m0, points[0]);
    var m1 = MidPoint(points[1], points[2]);
    smoothedPath.AddQuadCurveToPoint(m1, points[1]);
    var m2 = MidPoint(points[2], points[3]);
    smoothedPath.AddQuadCurveToPoint(m2, points[2]);
    var m3 = MidPoint(points[3], points[4]);
    smoothedPath.AddQuadCurveToPoint(m3, points[3]);
    var m4 = MidPoint(points[4], points[5]);
    smoothedPath.AddQuadCurveToPoint(m4, points[4]);
    var m5 = MidPoint(points[5], points[6]);
    smoothedPath.AddQuadCurveToPoint(m5, points[5]);
    var m6 = MidPoint(points[6], points[0]);
    smoothedPath.AddQuadCurveToPoint(m6, points[6]);
    
    smoothedPath.AddQuadCurveToPoint(m0, points[0]); 
    smoothedPath.ClosePath();
    
    color.SetStroke();
    smoothedPath.LineWidth = 5.0f;
    smoothedPath.Stroke();
    

    原文:

    1) 我不确定您正在寻找多少关节平滑,但LineJoinStyle 上的LineJoinStyleCGLineJoin.Round 会创建一个微妙的外观。

    2) 如果您需要重角平滑,您可以手动计算每条线的起点/终点,并添加一个 ArcWithCenter 来连接每条线段。

    3) 或者在不使用手动角弧计算的情况下,您可以在使用 CGLineJoin.Round 时设置非常粗的线宽,并稍微缩小绘图的大小以弥补增加的线宽。

    例子:

    var color = UIColor.FromRGBA(0.129f, 0.467f, 0.874f, 1.000f);
    
    UIBezierPath polygonPath = new UIBezierPath();
    polygonPath.MoveTo(new CGPoint(136.49f, 134.6f));
    polygonPath.AddLineTo(new CGPoint(197.04f, 20.0f));
    polygonPath.AddLineTo(new CGPoint(257.59f, 20.0f));
    polygonPath.AddLineTo(new CGPoint(303.0f, 134.6f));
    polygonPath.AddLineTo(new CGPoint(303.0f, 252.0f));
    polygonPath.AddLineTo(new CGPoint(28.0f, 252.0f));
    polygonPath.AddLineTo(new CGPoint(28.0f, 134.6f));
    polygonPath.AddLineTo(new CGPoint(136.49f, 134.6f));
    polygonPath.ClosePath();
    polygonPath.LineJoinStyle = CGLineJoin.Round;
    
    color.SetFill();
    polygonPath.Fill();
    color.SetStroke();
    polygonPath.LineWidth = 30.0f;
    polygonPath.Stroke();
    

    :中点法

    protected CGPoint MidPoint(CGPoint first, CGPoint second)
    {
        var x = (first.X + second.X) / 2;
        var y = (first.Y + second.Y) / 2;
        return new CGPoint(x: x, y: y);
    }
    

    【讨论】:

    • 感谢您的帮助,但我想我应该更具体一点。我正在寻找更多特定的曲线。我会更新我的问题,你会明白我的意思。
    • 再次感谢您的帮助。您更新后的答案看起来像我要找的,但MidPoint 是什么?这是你创建的方法吗?
    • @JaredPrice 我使用MidPoint 方法编辑了帖子。
    • 这太棒了。当我是 Adob​​e Illustrator“控制点”的设计师时,我使用四边形曲线,所以我理解这个原理。我包装了你的代码并尝试了它。最初,看起来原始连接越清晰,舍入越平滑。当您认为“控制点”更远时,这是可以理解的。 (至少我认为它是这样工作的)
    • 请记住,通过中点(递归)增加原始路径的点数,可以提高角度舍入的精度。
    猜你喜欢
    • 2017-09-22
    • 2023-03-25
    • 1970-01-01
    • 2018-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    相关资源
    最近更新 更多