一个更好的UGUI 竖排文本方案

今天遇到了一个需求,需要将文本竖排排列,查到了一个网上的方案
但是这个方案有几个问题(BUG)

  • 文本的位置会跟着锚点变化
  • 每行的最后几个字的布局是错的
  • 因为他是基于横版的文本排版结果,所以文本框的宽度也会影响他的换行,而且会造成文本框的大小范围和文本的不一致

于是我在他原来的思路上把它继续改进了下,并且增加了注释便于理解
思路就是重新实现一套排版机制,对换行符特殊处理,然后继续沿用原来修改顶点位置的方案。

using UnityEngine;  
using UnityEngine.UI;

[AddComponentMenu("UI/TextVerticalCompoent", 10)]
public class TextVerticalCompoent : Text  
{
    public bool m_Virtical = true;
    private float lineSpace = 1;
    private float textSpace = 1;
    private float xOffset = 0;
    private float yOffset = 0;

#if UNITY_EDITOR
    protected override void OnValidate()
    {
        base.OnValidate();

        //关闭自动裁切文本
        //解决有时裁切文本会出错的问题
        verticalOverflow = VerticalWrapMode.Overflow;
    }
#endif

    protected override void OnPopulateMesh(VertexHelper toFill)
    {
        base.OnPopulateMesh(toFill);
        if (m_Virtical)
        {
            VirticalText(toFill);
        }
    }

    private void VirticalText(VertexHelper toFill)
    {
        if (!IsActive())
            return;

        lineSpace = fontSize * lineSpacing;
        textSpace = fontSize ;

        //排除掉锚点变化造成的影响
        xOffset = rectTransform.rect.width + rectTransform.rect.x - fontSize / 2;
        yOffset = rectTransform.rect.height + rectTransform.rect.y - fontSize / 2;

        //重新计算一版排版
        int row = 0;
        int col = 0;
        float height = fontSize / 2;

        int minCount = toFill.currentVertCount / 4;

        if (rectTransform.rect.height < fontSize)
        {
            return;
        }

        for (int i = 0; i < minCount; i++)
        {
            if (height > rectTransform.rect.height || text[i] == '\n')
            {
                col++;
                row = 0;
                height = fontSize / 2;
            }

            ModifyText(toFill, i, row, col);

            if (text[i] != '\n')
            {
                row++;
                height += fontSize;
            }
        }
    }

    void ModifyText(VertexHelper helper, int i, int charYPos, int charXPos)
    {
        //Text 的绘制是每4个顶点绘制一个字符
        //按字符顺序取出顶点,则可以获得字符的位置
        //并对其进行修改

        //取出原来顶点的位置
        UIVertex lb = new UIVertex();
        helper.PopulateUIVertex(ref lb, i * 4);

        UIVertex lt = new UIVertex();
        helper.PopulateUIVertex(ref lt, i * 4 + 1);

        UIVertex rt = new UIVertex();
        helper.PopulateUIVertex(ref rt, i * 4 + 2);

        UIVertex rb = new UIVertex();
        helper.PopulateUIVertex(ref rb, i * 4 + 3);

        //计算文本的中心点
        Vector3 center = Vector3.Lerp(lb.position, rt.position, 0.5f);

        float x = -charXPos * lineSpace + xOffset;
        float y = -charYPos * textSpace + yOffset;

        //计算字符新位置
        Vector3 pos = new Vector3(x, y, 0);

        lb.position = lb.position - center + new Vector3(x, y, 0);
        lt.position = lt.position - center + new Vector3(x, y, 0);
        rt.position = rt.position - center + new Vector3(x, y, 0);
        rb.position = rb.position - center + new Vector3(x, y, 0);

        helper.SetUIVertex(lb, i * 4);
        helper.SetUIVertex(lt, i * 4 + 1);
        helper.SetUIVertex(rt, i * 4 + 2);
        helper.SetUIVertex(rb, i * 4 + 3);
    }
}

大功告成

也可以点击这里下载这个类

kisence

潮落江平未有风。