Unity图文混排实现

实现在文本中插入图片,图片替换符使用如下格式 //XML: &lt;quad index=0 size=60&gt;   代码中<quad index=0 size=60>

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

[RequireComponent(typeof(Text))]
public class TextTagHook : BaseMeshEffect
{
    public class SpriteTagInfo
    {
        public int index;
        public int stringIndex;
        public Vector2 size;
        public bool isVisible = true;
    }

    //in XML:  &lt;quad index=0 size=60&gt;   <quad index=0 size=60>
    private static readonly Regex spriteTagRegex = new Regex(@"<quad\s+index=(\d+)\s+size=(\d*\.?\d+%?)(\s+width=(\d*\.?\d+%?))?\s*>", RegexOptions.Singleline);
    private static readonly Regex spriteTagReplacementRegex = new Regex(@"{}", RegexOptions.Singleline);
    private static readonly Regex tagRegex = new Regex(@"<.*?>", RegexOptions.Singleline);
    private static readonly Regex whitespaceRegex = new Regex(@"\s+", RegexOptions.Singleline);

    public RectTransform[] tagObjects = new RectTransform[] { };

    private Text _text;
    public Text text
    {
        get
        {
            if (_text == null)
            {
                _text = GetComponent<Text>();
            }

            return _text;
        }
    }

    private List<SpriteTagInfo> spriteTags = new List<SpriteTagInfo>();

    private string lastContent;
    private bool lastBestFit;
    private int lastVertexCount;
    private bool isContentDirty
    {
        get
        {
            return true;
        }
    }

    private bool isValid;
    
    public override void ModifyMesh(VertexHelper vh)
    {
        if (!IsActive()) return;

        if (isContentDirty)
        {
            lastContent = text.text;
            lastBestFit = text.resizeTextForBestFit;
            lastVertexCount = text.cachedTextGenerator.vertexCount;

            spriteTags.Clear();
            try
            {
                foreach (Match match in spriteTagRegex.Matches(lastContent))
                {
                    SpriteTagInfo spriteTag = new SpriteTagInfo();
                    spriteTag.index = int.Parse(match.Groups[1].Value);
                    spriteTag.stringIndex = match.Index;
                    spriteTag.size = new Vector2(float.Parse(match.Groups[2].Value), float.Parse(match.Groups[2].Value));
                    if (match.Groups[4].Success)
                    {
                        spriteTag.size.x *= float.Parse(match.Groups[4].Value);
                    }
                    spriteTag.isVisible = text.cachedTextGenerator.vertexCount / 4 > spriteTag.stringIndex;
                    spriteTags.Add(spriteTag);
                }

                if (text.cachedTextGenerator.vertexCount / 4 != text.cachedTextGenerator.characterCount)
                {
                    string toGenerateContent = spriteTagRegex.Replace(lastContent, "{}");
                    toGenerateContent = tagRegex.Replace(toGenerateContent, string.Empty);
                    toGenerateContent = whitespaceRegex.Replace(toGenerateContent, string.Empty);
                    int index = 0;
                    foreach (Match match in spriteTagReplacementRegex.Matches(toGenerateContent))
                    {
                        spriteTags[index].stringIndex = match.Index - index;
                        spriteTags[index].isVisible = true;
                        index++;
                    }
                }
                isValid = true;
            }
            catch (System.Exception e)
            {
                isValid = false;
            }
        }

        for (int i = 0; i < tagObjects.Length; i++)
        {
            if (tagObjects[i] != null)
            {
                tagObjects[i].localScale = Vector3.zero;
            }
        }

        if (isValid)
        {
            for (int i = 0; i < spriteTags.Count; i++)
            {
                SpriteTagInfo spriteTag = spriteTags[i];

                if (tagObjects.Length > spriteTag.index)
                {
                    var target = tagObjects[spriteTag.index];
                    if (target == null) continue;

                    if (spriteTag.isVisible)
                    {
                        float unitsPerPixel = 1 / text.pixelsPerUnit;
                        var verts = text.cachedTextGenerator.verts;

                        Vector2 roundingOffset = new Vector2(verts[0].position.x, verts[0].position.y) * unitsPerPixel;
                        roundingOffset = text.PixelAdjustPoint(roundingOffset) - roundingOffset;

                        Vector3 pox1 = verts[spriteTag.stringIndex * 4 + 3].position;
                        Vector3 pox2 = verts[spriteTag.stringIndex * 4 + 2].position;
                        if (roundingOffset != Vector2.zero)
                        {
                            pox1 *= unitsPerPixel;
                            pox1.x += roundingOffset.x;
                            pox1.y += roundingOffset.y;
                            pox2 *= unitsPerPixel;
                            pox2.x += roundingOffset.x;
                            pox2.y += roundingOffset.y;
                        }
                        else
                        {
                            pox1 *= unitsPerPixel;
                            pox2 *= unitsPerPixel;
                        }

                        target.localPosition = pox1;
                        target.localScale = Vector3.one * (pox2.x - pox1.x) / spriteTag.size.x;
                    }
                }
            }

            List<UIVertex> vertexList = new List<UIVertex>();
            vh.GetUIVertexStream(vertexList);

            for (int i = 0; i < spriteTags.Count; i++)
            {
                if (!spriteTags[i].isVisible) continue;

                //UGUIText不支持<quad/>标签,表现为乱码,这里将他的uv全设置为0,清除乱码
                for (int m = spriteTags[i].stringIndex * 6; m < spriteTags[i].stringIndex * 6 + 6; m++)
                {
                    UIVertex tempVertex = vertexList[m];
                    tempVertex.uv0 = Vector2.zero;
                    tempVertex.uv1 = Vector2.zero;
                    tempVertex.uv2 = Vector2.zero;
                    tempVertex.uv3 = Vector2.zero;
                    tempVertex.color = Color.clear;
                    vertexList[m] = tempVertex;
                }
            }

            vh.Clear();
            vh.AddUIVertexTriangleStream(vertexList);
        }
    }
}

将脚本挂到Text上,如下图,可以通过调整icon1和icon2的位置来调整图片显示的位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值