SkiaSharp中启用多行属性的容器内文本绘制问题求助
SkiaSharp中启用多行属性的容器内文本绘制问题求助
各位好,我现在在使用SkiaSharp库做文本渲染,写了主渲染逻辑和多行文本的绘制方法,但在启用多行属性的容器里绘制文本时遇到了问题。以下是我的相关代码,希望大家能帮忙看看哪里出了问题:
首先是主渲染方法:
private void SendText(OggettoLayout oggetto, SKCanvas canvas, float dpi, bool antialiasingOff) { if (oggetto.StileTesto == null) throw new Exception(RenderMessages.LayoutNonValido); if (oggetto.StileTesto.IsNullHide && string.IsNullOrWhiteSpace(oggetto.Valore)) return; canvas.Save(); var text = oggetto.Valore ?? (oggetto.StileTesto.IsNullError ? "##VALORENULL##" : ""); float xDpi = oggetto.X * dpi; float yDpi = oggetto.Y * dpi; float widthDpi = oggetto.Larghezza * dpi; float heightDpi = oggetto.Altezza * dpi; var textContainer = new SKRect(xDpi, yDpi, xDpi + widthDpi, yDpi + heightDpi); var font = GetFont(oggetto, widthDpi, heightDpi, dpi); var paint = new SKPaint { IsAntialias = !antialiasingOff, Color = oggetto.StileTesto.Colore?.FromRgbaToSKColor() ?? SKColors.Black, IsStroke = false }; float textWidth = font.MeasureText(text, out SKRect bounds); float offsetX = textContainer.Left; float offsetY = textContainer.Top; switch (oggetto.StileTesto.Allineamento) { case AllineamentoTesto.Center: offsetX += (textContainer.Width - bounds.Width) / 2; break; case AllineamentoTesto.Right: offsetX += textContainer.Width - bounds.Width; break; } switch (oggetto.StileTesto.AllineamentoVerticale) { case AllineamentoVerticale.Top: offsetY += font.Size * 0.15f - bounds.Top; break; case AllineamentoVerticale.Center: offsetY += (textContainer.Height - bounds.Height) / 2 - bounds.Top; break; case AllineamentoVerticale.Bottom: offsetY += textContainer.Height - bounds.Bottom - font.Size * 0.25f; break; } if (_rotate180) { canvas.Translate(textContainer.MidX, textContainer.MidY); canvas.RotateDegrees(180); canvas.Translate(-textContainer.MidX, -textContainer.MidY); } if (oggetto.Orientamento > 0) { canvas.Translate(textContainer.MidX, textContainer.MidY); canvas.RotateDegrees(oggetto.Orientamento); canvas.Translate(-textContainer.MidX, -textContainer.MidY); } if (oggetto.Raggio > 0) { using var path = RoundedRectangle(textContainer, oggetto.Raggio * dpi); canvas.ClipPath(path); } else { canvas.ClipRect(textContainer); } if (oggetto.StileTesto.IsMultiLine) { if (oggetto.StileTesto.Allineamento == AllineamentoTesto.Justify) { DrawJustifiedText(text, textWidth, font, textContainer, oggetto, canvas, paint, offsetY); } else { DrawMultilineText(text, textWidth, font, textContainer, offsetX, oggetto, canvas, paint, offsetY); } } else { canvas.DrawText(text, offsetX, offsetY, font, paint); if (oggetto.StileTesto.IsUnderline) { using var underlinePaint = new SKPaint { Style = SKPaintStyle.Stroke, Color = paint.Color, StrokeWidth = font.Size * 0.07f, IsAntialias = true }; float underlineY = offsetY + font.Size * 0.1f; canvas.DrawLine(offsetX, underlineY, offsetX + bounds.Width, underlineY, underlinePaint); } } canvas.Restore(); //canvas.ResetMatrix(); }
然后是多行文本的绘制方法及辅助方法:
private void DrawMultilineText(string text, float textWidth, SKFont font, SKRect container, float startX, OggettoLayout oggetto, SKCanvas canvas, SKPaint paint, float offsetY) { var lines = GetWordsForRow(text, textWidth, font, container).ToList(); if (lines.Count == 0) return; float y = GetOffsetY(lines.Count, offsetY, container, oggetto.StileTesto.AllineamentoVerticale, font); float lineHeight = font.Metrics.Descent - font.Metrics.Ascent; if (lineHeight <= 0 || float.IsNaN(lineHeight)) lineHeight = font.Size * 1.2f; foreach (var line in lines) { float lineWidth = font.MeasureText(line, out SKRect lineBounds); float x = GetOffsetX(lineWidth, startX, oggetto.StileTesto.Allineamento, container, lineBounds); canvas.DrawText(line, x, y, font, paint); if (oggetto.StileTesto.IsUnderline) { using var underlinePaint = new SKPaint { Style = SKPaintStyle.Stroke, Color = paint.Color, StrokeWidth = font.Size * 0.07f, IsAntialias = true }; float underlineY = y + font.Size * 0.1f; canvas.DrawLine(x, underlineY, x + lineBounds.Width, underlineY, underlinePaint); } y += lineHeight; } } private float GetOffsetX(float lineWidth, float startX, AllineamentoTesto textAlignment, SKRect container, SKRect lineBounds) { float lineOffsetX = startX; switch (textAlignment) { case AllineamentoTesto.Left: lineOffsetX = startX; break; case AllineamentoTesto.Center: lineOffsetX = container.MidX - lineBounds.Width / 2; break; case AllineamentoTesto.Right: lineOffsetX = container.Right - lineBounds.Width; break; default: return startX; } return lineOffsetX; } private float GetOffsetY(int lineCount, float offsetY, SKRect container, AllineamentoVerticale alignment, SKFont font) { float ascent = font.Metrics.Ascent; float lineHeight = font.Metrics.Descent - font.Metrics.Ascent; switch (alignment) { case AllineamentoVerticale.Top: return offsetY; case AllineamentoVerticale.Bottom: return offsetY -= (lineCount - 1) * lineHeight; case AllineamentoVerticale.Center: // 注:原代码此处疑似输入截断,逻辑不完整 break; } return offsetY; }
目前启用多行属性后,文本绘制效果不符合预期,比如存在位置偏移、对齐错误或换行异常等问题。另外注意到GetOffsetY方法里的垂直居中分支代码不完整,这大概率也是问题诱因之一。
有没有大佬能帮忙排查下代码里的问题,或者给一些调试建议?
内容来源于stack exchange
相关产品推荐
相关产品推荐

