Unity UGUI实现图文混合 EmojiText

图文混合:利用quad标签

quad的属性可以正确设置图片大小,而quad的大小会自动排版,那么我们就可以用quad来做占位,进行图文混排的实现。
然后,使用在Text中图文混排,需要解决的问题。
第一,消除乱码。
第二,用正确的图片替换占位符。
第三,控制占位符大小。

功能基本实现,目前存在的问题是编辑器状态下无法预览。。

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

class MyQuadTagInfo
{
    public int startIndex;
    public string name;
    public float size;
    public Image img;
    public bool isActive;
    public void SetActive(bool active)
    {
        img.gameObject.SetActive(active);
    }
}

public class MyEmojiText : Text {
    /// <summary>
    /// 解析#name#size#width
    /// </summary>
    private static readonly Regex s_SimpleQuadRegex = new Regex(@"\[#((#?\w*\.?\d*%?)*)\]", RegexOptions.Singleline);
    /// <summary>
    /// 解析quad 找到对应的渲染顶点
    /// </summary>
    private static readonly Regex s_QuadRegex = new Regex(@"<quad name=(\w*) size=(\d*\.?\d+%?) width=(\d*\.?\d+%?) />", RegexOptions.Singleline);
    private List<MyQuadTagInfo> MyQuadTagInfos = new List<MyQuadTagInfo>();
    private string outputText = ""; //解析完后的字符串

    private TextGenerationSettings TextGenerationSettings;

    readonly UIVertex[] m_TempVerts = new UIVertex[4];

    protected override void OnEnable()//编辑器下调试使用
    {
        base.OnEnable();
#if UNITY_EDITOR
        ParseText();
#endif
    }
    public override void SetVerticesDirty()
    {
        if (!IsActive())
        {
            return;
        }
        ParseText();
        base.SetVerticesDirty();
    }
    private void ParseText()
    {
        outputText = "";
        string []splitArr;
        string tmpName;
        string tmpSize;
        string tmpWidth;

        int startIndex = 0;
        foreach (Match match in s_SimpleQuadRegex.Matches(text))
        {
            splitArr = match.Groups[1].Value.Split('#');
            tmpSize = (splitArr.Length >= 3) ? splitArr[2] : fontSize.ToString();
            tmpWidth = (splitArr.Length >= 2) ? splitArr[1] : "1";
            tmpName = (splitArr.Length >= 1) ? splitArr[0] : "0";
            outputText += text.Substring(startIndex, match.Index - startIndex) + string.Format("<quad name={0} size={1} width={2} />", tmpName, tmpSize, tmpWidth == "" ? "1" : tmpWidth);
            startIndex = match.Index + match.Length;
        }

        outputText += text.Substring(startIndex, text.Length - startIndex);
        ParseQuad();
    }

    private void ParseQuad()
    {
        int index = 0;
        foreach (Match match in s_QuadRegex.Matches(outputText))
        {
            float size = float.Parse(match.Groups[2].Value);
            float width = float.Parse(match.Groups[3].Value);
            if (MyQuadTagInfos.Count < index + 1)
            {
                MyQuadTagInfos.Add(new MyQuadTagInfo());
            }
            MyQuadTagInfo quadTagInfo = MyQuadTagInfos[index];
            quadTagInfo.name = match.Groups[1].Value;
            quadTagInfo.size = size;
            quadTagInfo.startIndex = match.Index;
            quadTagInfo.isActive = true;
            index++;
        }

        for (int i = index; i < MyQuadTagInfos.Count; i++)
        {
            MyQuadTagInfos[i].isActive = false;
        }
        if (Application.isPlaying)
        {
            CreateImage();
        }
    }

    private void CreateImage()
    {
        foreach (var i in MyQuadTagInfos)
        {
            i.SetActive(false); 
            var sprite = Resources.Load<Sprite>("Emoji/" + i.name);
            if (i.isActive && sprite)
            {
                i.SetActive(true);
                if (i.img == null)
                {
                    var icon = new GameObject().AddComponent<Image>();
                    icon.transform.SetParent(this.transform);
                    i.img = icon;
                }
                i.img.sprite = sprite;
                i.img.GetComponent<RectTransform>().sizeDelta = new Vector2(i.size, i.size);
                i.img.transform.localScale = Vector3.one;
            }
        }
    }

    private void ClearQuad(IList<UIVertex> verts)
    {
        foreach (var quad in MyQuadTagInfos)
        {
            if (!quad.isActive)
            {
                continue;
            }
            int startIndex = quad.startIndex * 4;
            int endIndex = startIndex + 4;
            for (int i = startIndex; i <= endIndex; i++)
            {
                if (i >= verts.Count)
                {
                    continue;
                }
                verts[i] = verts[startIndex];
            }
        }
    }

    private void UpdataQuadPos(VertexHelper mVertexHelperRef)
    {
        foreach (var quad in MyQuadTagInfos)
        {
            if (!quad.isActive || quad.img == null)
            {
                continue;
            }
            int startIndex = quad.startIndex * 4;
            UIVertex vert = new UIVertex();
            mVertexHelperRef.PopulateUIVertex(ref vert, startIndex);
            var width = quad.size;
            quad.img.GetComponent<RectTransform>().anchoredPosition3D = vert.position + new Vector3(width/2, -width/2 - width/10);
        }
    }

    protected override void OnPopulateMesh(VertexHelper toFill)
    {
        //一下为原OnPopulateMesh函数
        if (font == null)
            return;
        // We don't care if we the font Texture changes while we are doing our Update.
        // The end result of cachedTextGenerator will be valid for this instance.
        // Otherwise we can get issues like Case 619238.
        m_DisableFontTextureRebuiltCallback = true;

        Vector2 extents = rectTransform.rect.size;

        var settings = GetGenerationSettings(extents);
        cachedTextGenerator.PopulateWithErrors(outputText, settings, gameObject);

        // Apply the offset to the vertices
        IList<UIVertex> verts = cachedTextGenerator.verts;
        float unitsPerPixel = 1 / pixelsPerUnit;
        int vertCount = verts.Count - 4;

        ClearQuad(verts); //清除乱码的quad并且创建图片
        // We have no verts to process just return (case 1037923)
        if (vertCount <= 0)
        {
            toFill.Clear();
            return;
        }

        Vector2 roundingOffset = new Vector2(verts[0].position.x, verts[0].position.y) * unitsPerPixel;
        roundingOffset = PixelAdjustPoint(roundingOffset) - roundingOffset;
        toFill.Clear();
        if (roundingOffset != Vector2.zero)
        {
            for (int i = 0; i < vertCount; ++i)
            {
                int tempVertsIndex = i & 3;
                m_TempVerts[tempVertsIndex] = verts[i];
                m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                m_TempVerts[tempVertsIndex].position.x += roundingOffset.x;
                m_TempVerts[tempVertsIndex].position.y += roundingOffset.y;
                if (tempVertsIndex == 3)
                    toFill.AddUIVertexQuad(m_TempVerts);
            }
        }
        else
        {
            for (int i = 0; i < vertCount; ++i)
            {
                int tempVertsIndex = i & 3;
                m_TempVerts[tempVertsIndex] = verts[i];
                m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                if (tempVertsIndex == 3)
                    toFill.AddUIVertexQuad(m_TempVerts);
            }
        }
        UpdataQuadPos(toFill);
        m_DisableFontTextureRebuiltCallback = false;
    }
}


效果图
在这里插入图片描述 emoji图片在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张_0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值