You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MAUI应用中FillPath忽略看似闭合路径内贝塞尔曲线的问题

路径填充失败:顶部环绕居中按钮的条形无法闭合填充

我需要绘制一个顶部环绕居中按钮的条形,已通过直线和贝塞尔曲线构建PathF对象,调用DrawPath能正常绘制轮廓,但调用FillPath时,路径因未被识别为闭合状态而无法填充。

DrawPath效果:
DrawPath效果
FillPath效果:
FillPath效果

尝试调整代码近一小时仍未解决,以下是相关代码:


问题代码

IDrawable的Draw方法:

public void Draw(ICanvas canvas, RectF dirtyRect)
{
    float buttonSize = 80;
    float width = dirtyRect.Width;
    float height = dirtyRect.Height;
    canvas.StrokeColor = Colors.Red;
    canvas.FillColor = Colors.Blue;
    canvas.StrokeSize = 1;

    float y1 = height / 2; // bar top 
    float tX = width / 2; // x translation applied to all bezier curve points
    float tY = height / 2; // y translation applied to all bezier curve points
    float r = buttonSize * 1.5f / 2; // radius
    float c = 0.5522847498307933984022516322796f;

    float segmentWidth = (width - (r * 2)) / 2;

    PathF path = new PathF(0, y1);

    path.LineTo(segmentWidth, y1);            //  _____
    path.MoveTo(width - segmentWidth, y1);    //          x
    path.LineTo(width, y1);                   //           _____
    path.LineTo(width, height);               //               |
    path.LineTo(0, height);                   //  --------------
    path.LineTo(0, y1);                       // |


    path.MoveTo(r + tX, 0 + tY);
    path.CurveTo(r + tX, c * r + tY,
        c * r + tX, r + tY,
        0 + tX, r + tY);

    path.MoveTo(0 + tX, r + tY);
    path.CurveTo(-c * r + tX, r + tY,
        -r + tX, c * r + tY,
        -r + tX, 0 + tY);

    canvas.FillPath(path);
}

布局代码:

<Grid ColumnDefinitions="*, Auto, *" RowDefinitions="*, 15*, 200">
    <Button Grid.Row="0" Text="Draw" Clicked="Button_Clicked"/>
    <Grid Grid.Row="2" Grid.ColumnSpan="3" Padding="10, 10">
        <GraphicsView x:Name="bottomBar" Grid.ColumnSpan="3"/>
    </Grid>
</Grid>

解决方案

问题核心是你的路径是多个不连通的子路径,顶部曲线和下方条形没有连续连接,填充算法无法识别为单一闭合区域。需要移除不必要的MoveTo,让所有路径点连成一个连续的闭合环:

修改后的Draw方法代码:

public void Draw(ICanvas canvas, RectF dirtyRect)
{
    float buttonSize = 80;
    float width = dirtyRect.Width;
    float height = dirtyRect.Height;
    canvas.StrokeColor = Colors.Red;
    canvas.FillColor = Colors.Blue;
    canvas.StrokeSize = 1;

    float y1 = height / 2; // bar top 
    float tX = width / 2; // x translation applied to all bezier curve points
    float tY = height / 2; // y translation applied to all bezier curve points
    float r = buttonSize * 1.5f / 2; // radius
    float c = 0.5522847498307933984022516322796f;

    float segmentWidth = (width - (r * 2)) / 2;

    PathF path = new PathF(0, y1);

    // 左侧条形到曲线起点
    path.LineTo(segmentWidth, y1);
    // 右侧下半圆曲线
    path.CurveTo(c * r + tX, r + tY,
                 r + tX, c * r + tY,
                 r + tX, 0 + tY);
    // 上半圆曲线
    path.CurveTo(r + tX, -c * r + tY,
                 c * r + tX, -r + tY,
                 0 + tX, -r + tY);
    // 左侧下半圆曲线
    path.CurveTo(-c * r + tX, -r + tY,
                 -r + tX, -c * r + tY,
                 -r + tX, 0 + tY);
    // 连接到右侧条形起点
    path.CurveTo(-r + tX, c * r + tY,
                 -c * r + tX, r + tY,
                 width - segmentWidth, y1);
    // 右侧条形到右下角
    path.LineTo(width, y1);
    path.LineTo(width, height);
    // 底部到左下角
    path.LineTo(0, height);
    // 闭合路径回到起点
    path.LineTo(0, y1);

    canvas.FillPath(path);
}

关键说明

  • 移除所有非必要的MoveTo,保证路径从起点开始连续绘制
  • 调整贝塞尔曲线的顺序,让每段曲线的起点与前一段的终点重合,形成连续的环绕部分
  • 最后通过LineTo回到初始点,确保路径完全闭合

内容的提问来源于stack exchange,提问作者Toto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 13:00:35