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不显示问题
填充未覆盖星形:
- 确认
SKPaint.Style设置为SKPaintStyle.Fill(而非Stroke); - 检查SVG路径是否闭合,若未闭合,调用
starPath.Close()手动闭合。
- 确认
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
相关产品推荐
相关产品推荐

