Unity UGUI 文本 特殊文字添加事件

最终效果:
这是显示的文本
在这里插入图片描述
鼠标移上事件文字 “百鬼夜行” 后,控制台打印:
在这里插入图片描述
鼠标点击事件文字 “百鬼夜行” 后,控制台打印:
在这里插入图片描述
鼠标移出事件文字 “百鬼夜行” 后,控制台打印:
在这里插入图片描述

(一)主脚本:mTextPro.cs;调用脚本内的SetText()函数传参数就可以了。使用方法见步骤(二)

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

public class mTextPro : Text, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler
{
    
    
    private enum eventDataType
    {
    
    
        None,
        Enter,
        Exit,
        Click,
    }

    /// <summary>
    /// 超链接信息类
    /// </summary>
    private class TextProInfo
    {
    
    
        public int startIndex;

        public int endIndex;

        public string name;

        public readonly List<Rect> boxes = new List<Rect>();
    }

    /// <summary>
    /// 正则表达式
    /// </summary>
    private readonly Regex s_HrefRegex = new Regex(@"<a href=([^>\n\s]+)>(.*?)(</a>)", RegexOptions.Singleline);

    /// <summary>
    /// 解析完最终的文本
    /// </summary>
    private string m_OutputText;

    /// <summary>
    /// 文本信息列表
    /// </summary>
    private List<TextProInfo> m_HrefInfos = new List<TextProInfo>();

    /// <summary>
    /// 文本构造器
    /// </summary>
    protected StringBuilder s_TextBuilder = new StringBuilder();

    /// <summary>
    /// 鼠标点击事件文字
    /// </summary>
    private UnityAction clickAction;
    /// <summary>
    /// 鼠标移入事件文本
    /// </summary>
    private UnityAction enterAction;
    /// <summary>
    /// 鼠标移出事件文本
    /// </summary>
    private UnityAction exitAction;

    /// <summary>
    /// 事件文字的颜色
    /// </summary>
    private string eventStrColor = "#FF9900";

    /// <summary>
    /// 时间文本替代字符
    /// </summary>
    public string EventStrReplace => "{eventStr}";

    /// <summary>
    /// 文本信息
    /// </summary>
    private string textMessage;

    /// <summary>
    /// 当前鼠标事件
    /// </summary>
    private PointerEventData curEventData;

    /// <summary>
    /// 当前鼠标事件的类型
    /// </summary>
    private eventDataType curEventDataType;


    public void SetText(string messageStr, string eventStr, string eventColor, UnityAction clickAc, UnityAction enterAc, UnityAction exitAc)
    {
    
    
        string tempStr = string.Format("<a href=事件文本>[{0:name}]</a>", eventStr);
        textMessage = messageStr.Replace(EventStrReplace, tempStr);
        if (string.IsNullOrWhiteSpace(eventColor))
        {
    
    
            eventStrColor = "#FF9900";
        }
        else
        {
    
    
            eventStrColor = eventColor;
        }

        clickAction = clickAc;
        enterAction = enterAc;
        exitAction = exitAc;
        SetVerticesDirty();
    }

    public override void SetVerticesDirty()
    {
    
    
        base.SetVerticesDirty();
        text = textMessage;
        m_OutputText = GetOutputText(text);

    }

    private void OnGUI()
    {
    
    
        chackEventData();
    }


    protected override void OnPopulateMesh(VertexHelper toFill)
    {
    
    
        string orignText = m_Text;
        m_Text = m_OutputText;
        base.OnPopulateMesh(toFill);
        m_Text = orignText;
        UIVertex vert = new UIVertex();

        // 处理文本包围框
        for (int i = 0; i < m_HrefInfos.Count; i++)
        {
    
    
            m_HrefInfos[i].boxes.Clear();
            if (m_HrefInfos[i].startIndex >= toFill.currentVertCount)
            {
    
    
                continue;
            }

            // 将事件文本里面的文本顶点索引坐标加入到包围框
            toFill.PopulateUIVertex(ref vert, m_HrefInfos[i].startIndex);
            Vector3 pos = vert.position;
            Bounds bounds = new Bounds(pos, Vector3.zero);
            for (int TEMP = m_HrefInfos[i].startIndex, m = m_HrefInfos[i].endIndex; TEMP < m; TEMP++)
            {
    
    
                if (TEMP >= toFill.currentVertCount)
                {
    
    
                    break;
                }

                toFill.PopulateUIVertex(ref vert, TEMP);
                pos = vert.position;
                if (pos.x < bounds.min.x) // 换行重新添加包围框
                {
    
    
                    m_HrefInfos[i].boxes.Add(new Rect(bounds.min, bounds.size));
                    bounds = new Bounds(pos, Vector3.zero);
                }
                else
                {
    
    
                    bounds.Encapsulate(pos); // 扩展包围框
                }
            }
            m_HrefInfos[i].boxes.Add(new Rect(bounds.min, bounds.size));
        }
    }

    /// <summary>
    /// 获取超链接解析后的最后输出文本
    /// </summary>
    /// <returns></returns>
    protected virtual string GetOutputText(string outputText)
    {
    
    
        s_TextBuilder.Length = 0;
        m_HrefInfos.Clear();
        var indexText = 0;
        foreach (Match match in s_HrefRegex.Matches(outputText))
        {
    
    
            s_TextBuilder.Append(outputText.Substring(indexText, match.Index - indexText));
            s_TextBuilder.Append("<color=" + eventStrColor + ">");  // 事件文本颜色

            var group = match.Groups[1];
            TextProInfo hrefInfo = new TextProInfo
            {
    
    
                startIndex = s_TextBuilder.Length * 4, // 超链接里的文本起始顶点索引
                endIndex = (s_TextBuilder.Length + match.Groups[2].Length - 1) * 4 + 3,
                name = group.Value
            };
            m_HrefInfos.Add(hrefInfo);

            s_TextBuilder.Append(match.Groups[2].Value);
            s_TextBuilder.Append("</color>");
            indexText = match.Index + match.Length;
        }
        s_TextBuilder.Append(outputText.Substring(indexText, outputText.Length - indexText));
        return s_TextBuilder.ToString();
    }

    /// <summary>
    /// 点击事件检测是否点击到超链接文本
    /// </summary>
    /// <param name="eventData"></param>
    public void OnPointerClick(PointerEventData eventData)
    {
    
    
        curEventData = eventData;
        curEventDataType = eventDataType.Click;
    }
    public void OnPointerEnter(PointerEventData eventData)
    {
    
    
        curEventData = eventData;
        curEventDataType = eventDataType.Enter;
    }

    public void OnPointerExit(PointerEventData eventData)
    {
    
    
        curEventData = eventData;
        curEventDataType = eventDataType.Exit;
    }


    /// <summary>
    /// 检测事件
    /// </summary>
    private void chackEventData()
    {
    
    
        if (curEventData == null) return;


        Vector2 lp = Vector2.zero;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, curEventData.position, curEventData.pressEventCamera, out lp);

        foreach (var hrefInfo in m_HrefInfos)
        {
    
    
            var boxes = hrefInfo.boxes;
            for (var i = 0; i < boxes.Count; ++i)
            {
    
    
                if (boxes[i].Contains(lp))
                {
    
    
                    if (curEventDataType == eventDataType.Click)
                    {
    
    
                        clickAction?.Invoke();
                        curEventDataType = eventDataType.Exit;
                    }
                    if (curEventDataType == eventDataType.Enter || curEventDataType == eventDataType.None)
                    {
    
    
                        enterAction?.Invoke();
                        curEventDataType = eventDataType.Exit;
                    }
                    return;
                }
            }
        }

        if (curEventDataType == eventDataType.Exit)
        {
    
    
            exitAction?.Invoke();
        }

        curEventDataType = eventDataType.None;
    }
}

(二):将上面的mTextPro.cs;挂载到一个ui物体上:
在这里插入图片描述
新建ProjectTest .cs

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

public class ProjectTest : MonoBehaviour
{
    
    
    public mTextPro textPic;

    private void Start()
    {
    
    
        textPic.SetText("--这里显示的是当前选择的" + textPic.EventStrReplace + "任务", "百鬼夜行", "", mouseClick, mouseEnter, mouseExit);
    }


    private void mouseEnter()
    {
    
    
        Debug.Log("鼠标移入任务名称");
    }

    private void mouseExit()
    {
    
    
        Debug.Log("鼠标移出任务名称");
    }

    private void mouseClick()
    {
    
    
        print("鼠标点击了任务名称");
    }
}

将该脚本挂载到任一物体上,把对象上赋值,运行项目进行测试
在这里插入图片描述
用鼠标进行事件文本的交互,就可以看到效果了:
在这里插入图片描述

ps:我是根据这位仁兄的文章改动的。

其他方式也可以实现此功能,我这是在网上找的相关博客自己总结的,如果哪位路过的大佬有更简单的实现,还望评论告知:多谢(抱拳)。

猜你喜欢

转载自blog.csdn.net/a0_67/article/details/117825693