UGUI中为Text增加下划线

  今天遇到一个需要给UIText添加删除线的功能,以前博主一般是制作一个同样宽度的Image,盖在Text上,但是这次需要动态换行,所以就重写了Text的功能,具体代码如下。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class DeleteLineText : Text
{
    public float distance = 4f;
    public float lineHeight = 4f;
    public Color underLineColor;
    private bool useUnderLineColor = true;

    private List<UIVertex> textVertArr = new List<UIVertex>();
    private int startIndex = 0;
    private int endIndex = 0;

    protected override void Start()
    {
        base.Start();
        underLineColor = Color.red;
        lineHeight = 5.0f;
        distance = -15.0f;
    }

    protected override void OnPopulateMesh(VertexHelper toFill)
    {
        base.OnPopulateMesh(toFill); //渲染text字体的顶点
        toFill.GetUIVertexStream(textVertArr); //toFill创建vertex流  vertex数组的长度是文字长度的6倍 因为一个文字有六个顶点
        if (textVertArr.Count <= 0) return;
        SetUnderLine(toFill);
    }

    private void SetUnderLine(VertexHelper vh)
    {
        if(m_Text.Length <= 0)
        {
            return;
        }
        endIndex = m_Text.Length - 1;
        List<int> lineStartList = new List<int>();
        List<int> lineEndList = new List<int>();

        SavePosByCharacter(ref lineStartList, ref lineEndList);
        if (lineStartList.Count == 1)
        {
            // 单个字
            Vector2 startPos = new Vector2(textVertArr[lineStartList[0]].position.x, textVertArr[lineStartList[0]].position.y);
            Vector2 endPos = new Vector2(textVertArr[lineEndList[0]].position.x, textVertArr[lineEndList[0]].position.y);
            DrawLine(vh, startPos, endPos);
        }
        else
        {
            // 多个字
            for (int i = 0; i < lineStartList.Count; i++)
            {
                Vector2 startPos = new Vector2(textVertArr[lineStartList[i]].position.x, textVertArr[lineStartList[i]].position.y);
                Vector2 endPos = new Vector2(textVertArr[lineEndList[i]].position.x, textVertArr[lineEndList[i]].position.y);
                DrawLine(vh, startPos, endPos);
            }
        }
    }

    private void SavePosByCharacter(ref List<int> lineStartList, ref List<int> lineEndList)
    {
        // 对于每一个字处理 
        for (int i = startIndex; i <= endIndex; i++)
        {
            // 得到最底下的两个点
            int minPos = i * 6;
            int maxPos = i * 6;
            for (int j = i * 6; j < (i + 1) * 6; j++)
            {
                if (textVertArr[j].position.x < textVertArr[minPos].position.x)
                {
                    minPos = j;
                }
                else if (Mathf.Approximately(textVertArr[minPos].position.x, textVertArr[j].position.x)&& textVertArr[j].position.y < textVertArr[minPos].position.y)
                {
                    minPos = j;
                }

                if (textVertArr[j].position.x > textVertArr[maxPos].position.x)
                {
                    maxPos = j;
                }
                else if (Mathf.Approximately(textVertArr[maxPos].position.x, textVertArr[j].position.x) && textVertArr[j].position.y < textVertArr[maxPos].position.y)
                {
                    maxPos = j;
                }
            }
            lineStartList.Add(minPos);
            lineEndList.Add(maxPos); 
        }
    }

    private void DrawLine(VertexHelper vh, Vector2 startPos, Vector2 endPos)
    {
        Vector2 extents = rectTransform.rect.size;
        var setting = GetGenerationSettings(extents);

        TextGenerator underlineText = new TextGenerator();
        underlineText.Populate("-", setting);

        if (distance > fontSize && lineHeight > font.fontSize)
        {
            Debug.LogError("UnderLine property is Error! please make Certain property can't greater than fontSize.");
            return;
        }

        IList<UIVertex> lineVer = underlineText.verts;/*new UIVertex[4];*///"_"的的顶点数组

        Vector3[] pos = new Vector3[4];
        pos[0] = startPos + new Vector2(-8, -distance);
        pos[3] = startPos + new Vector2(-8, -(distance + lineHeight));
        pos[2] = endPos + new Vector2(8, -(distance + lineHeight));
        pos[1] = endPos + new Vector2(8, -distance);


        Color tempColor = useUnderLineColor ? underLineColor : color;
        UIVertex[] tempVerts = new UIVertex[4];
        for (int i = 0; i < 4; i++)
        {
            tempVerts[i] = lineVer[i];
            tempVerts[i].color = tempColor;
            tempVerts[i].position = pos[i];
            tempVerts[i].uv0 = lineVer[i].uv0;
            tempVerts[i].uv1 = lineVer[i].uv1;
            tempVerts[i].uv2 = lineVer[i].uv2;
            tempVerts[i].uv3 = lineVer[i].uv3;
        }
        vh.AddUIVertexQuad(tempVerts);
    }
}

大体思路是这样的,首先我们通过toFill.GetUIVertexStream(textVertArr)获取到了所有文字的顶点,这个数组的数量应该是文字数量的6倍,因为每个文字都由两个三角形也就是六个顶点构成。

然后通过比较,找到每个文字底部最小的位置和最大的位置,并把它们存储到一个数组中。接下来,我们重写Text的OnPopulateMesh函数,在这个函数中,为Text增加顶点。增加的逻辑是对于每一个文字,都在它底部的最小位置和最大位置之间增加四个点,组成一个长方形,也就是我们需要的下划线。

有的博主会把同一行的下划线变成四个点,博主试过这个做法,性能比较好,但是效果有一些问题,在下划线的两端,会有一个明显的渐变效果,所以我选择了对每个文字制作一个下划线,但是这样导致在改变文字的时候FPS的下降,算是各有利弊吧。

最后我们把下划线的位置上移,也就得到了我们的删除线。感觉这个算法还是有些问题,未来有更好的方法会继续更新的。

猜你喜欢

转载自blog.csdn.net/HelloCSDN666/article/details/124945927