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

SkiaSharp设置画布中心为旋转点并绕其旋转的实现问题

解决方案:SkiaSharp SVG旋转、适配及绘制异常修复

一、解决SVG倒置与180度旋转问题(替代过时的PostConcat)

SkiaSharp默认以左上角为原点,Y轴向下,这是SVG显示倒置的核心原因。绕中心旋转180度可直接解决,推荐用画布状态保存/变换方法(比手动拼接矩阵更直观):

private void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
    var canvas = e.Surface.Canvas;
    canvas.Clear();

    // 获取当前画布实时尺寸
    var info = e.Info;
    float canvasCenterX = info.Width / 2f;
    float canvasCenterY = info.Height / 2f;

    // 加载星形SVG路径
    SKPath starPath = LoadStarSvg();
    SKRect pathBounds = starPath.Bounds;
    float pathCenterX = pathBounds.MidX;
    float pathCenterY = pathBounds.MidY;

    // 保存画布当前状态,避免影响后续绘制
    canvas.Save();

    // 1. 将路径平移到画布中心(可选,按需调整)
    canvas.Translate(canvasCenterX - pathCenterX, canvasCenterY - pathCenterY);
    // 2. 绕路径自身中心旋转180度
    canvas.RotateDegrees(180, pathCenterX, pathCenterY);

    // 绘制填充星形
    using (var fillPaint = new SKPaint 
    { 
        Style = SKPaintStyle.Fill, 
        Color = SKColors.Gold,
        IsAntialias = true // 开启抗锯齿,优化边缘显示
    })
    {
        canvas.DrawPath(starPath, fillPaint);
    }

    // 绘制StarShine(注意顺序,避免被填充层覆盖)
    using (var shinePaint = new SKPaint 
    { 
        Style = SKPaintStyle.Stroke, 
        Color = SKColors.White, 
        StrokeWidth = 3,
        IsAntialias = true
    })
    {
        SKPath starShinePath = LoadStarShineSvg();
        canvas.DrawPath(starShinePath, shinePaint);
    }

    // 恢复画布初始状态
    canvas.Restore();
}

若需用矩阵组合替代PostConcat,使用SKMatrix.Concat:

// 创建绕路径中心的旋转矩阵
var rotateMat = SKMatrix.MakeRotationDegrees(180, pathCenterX, pathCenterY);
// 创建将路径移到画布中心的平移矩阵
var translateMat = SKMatrix.MakeTranslation(canvasCenterX - pathCenterX, canvasCenterY - pathCenterY);
// 组合矩阵(先平移再旋转)
var combinedMat = SKMatrix.Concat(translateMat, rotateMat);
// 应用到画布
canvas.Concat(combinedMat);

二、解决画布尺寸变化导致的布局混乱

每次绘制必须基于e.Info获取的实时画布尺寸,禁止使用固定宽高值。同时确保SKCanvasView的布局属性设置为自适应:

<!-- XAML中配置SKCanvasView布局 -->
<skia:SKCanvasView 
    PaintSurface="OnCanvasViewPaintSurface"
    HorizontalOptions="FillAndExpand"
    VerticalOptions="FillAndExpand" />

三、修复填充未覆盖星形、StarShine不显示问题

  1. 填充未覆盖星形:

    • 确认SKPaint.Style设置为SKPaintStyle.Fill(而非Stroke);
    • 检查SVG路径是否闭合,若未闭合,调用starPath.Close()手动闭合。
  2. StarShine不显示:

    • 调整绘制顺序:若为发光效果,建议先绘制StarShine再绘制星形填充;
    • 验证SKPaint参数:颜色需与背景有足够对比度,StrokeWidth设置合理(不要过小);
    • 确保StarShine路径应用了和星形相同的旋转/平移变换,避免被移出画布;
    • 临时将StarShine颜色设为红色,排查路径位置是否正确。

四、封装通用旋转路径方法

将旋转逻辑封装为工具类,便于复用:

public static class SkiaUtils
{
    /// <summary>
    /// 绕指定中心旋转路径
    /// </summary>
    /// <param name="sourcePath">原路径</param>
    /// <param name="degrees">旋转角度(顺时针为正)</param>
    /// <param name="centerX">旋转中心X坐标</param>
    /// <param name="centerY">旋转中心Y坐标</param>
    /// <returns>旋转后的新路径</returns>
    public static SKPath RotatePath(SKPath sourcePath, float degrees, float centerX, float centerY)
    {
        var rotatedPath = new SKPath();
        var transform = SKMatrix.MakeRotationDegrees(degrees, centerX, centerY);
        rotatedPath.AddPath(sourcePath, transform);
        return rotatedPath;
    }

    /// <summary>
    /// 在画布上应用旋转变换(需手动调用Restore恢复状态)
    /// </summary>
    public static void RotateCanvas(SKCanvas canvas, float degrees, float centerX, float centerY)
    {
        canvas.Save();
        canvas.RotateDegrees(degrees, centerX, centerY);
    }
}

使用示例:

// 方式1:直接获取旋转后的路径
var rotatedStar = SkiaUtils.RotatePath(starPath, 180, pathCenterX, pathCenterY);
canvas.DrawPath(rotatedStar, fillPaint);

// 方式2:临时变换画布
SkiaUtils.RotateCanvas(canvas, 180, canvasCenterX, canvasCenterY);
canvas.DrawPath(starPath, fillPaint);
canvas.Restore();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 19:10:50