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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 03:09:44