• 转载 Unity Text 插入超链接


    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Text.RegularExpressions;
    using UnityEngine;
    using UnityEngine.Events;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    
    /// <summary>
    /// 文本控件,支持超链接、图片
    /// </summary>
    [AddComponentMenu("UI/Text_Pro", 10)]
    public class Text_Pro : Text, IPointerClickHandler
    {
        /// <summary>
        /// 解析完最终的文本
        /// </summary>
        private string m_OutputText;
    
        /// <summary>
        /// 图片池
        /// </summary>
        protected readonly List<Image> m_ImagesPool = new List<Image>();
    
        /// <summary>
        /// 图片的最后一个顶点的索引
        /// </summary>
        private readonly List<int> m_ImagesVertexIndex = new List<int>();
    
        /// <summary>
        /// 超链接信息列表
        /// </summary>
        private readonly List<HrefInfo> m_HrefInfos = new List<HrefInfo>();
    
        /// <summary>
        /// 文本构造器
        /// </summary>
        protected static readonly StringBuilder s_TextBuilder = new StringBuilder();
    
        [Serializable]
        public class HrefClickEvent : UnityEvent<string> { }
    
        [SerializeField]
        private HrefClickEvent m_OnHrefClick = new HrefClickEvent();
    
        /// <summary>
        /// 超链接点击事件
        /// </summary>
        public HrefClickEvent onHrefClick
        {
            get { return m_OnHrefClick; }
            set { m_OnHrefClick = value; }
        }
    
        /// <summary>
        /// 正则-图片
        /// </summary>
        private static readonly Regex s_ImageRegex =
            new Regex(@"<quad name=(.+?) size=(d*.?d+%?) width=(d*.?d+%?) />", RegexOptions.Singleline);
    
        /// <summary>
        /// 正则-超链接
        /// </summary>
        private static readonly Regex s_HrefRegex =
            new Regex(@"<a href=([^>
    s]+)>(.*?)(</a>)", RegexOptions.Singleline);
    
    
        /// <summary>
        /// 加载精灵图片方法
        /// </summary>
        public static Func<string, Sprite> funLoadSprite;
    
        public override void SetVerticesDirty()
        {
            base.SetVerticesDirty();
            UpdateQuadImage();
        }
    
        protected void UpdateQuadImage()
        {
    #if UNITY_EDITOR
            if (UnityEditor.PrefabUtility.GetPrefabType(this) == UnityEditor.PrefabType.Prefab)
            {
                return;
            }
    #endif
    
            m_OutputText = GetOutputText(text);
            m_ImagesVertexIndex.Clear();
            foreach (Match match in s_ImageRegex.Matches(m_OutputText))
            {
                var picIndex = match.Index;
                var endIndex = picIndex * 4 + 3;
                m_ImagesVertexIndex.Add(endIndex);
    
                m_ImagesPool.RemoveAll(image => image == null);
                if (m_ImagesPool.Count == 0)
                {
                    GetComponentsInChildren<Image>(m_ImagesPool);
                }
                if (m_ImagesVertexIndex.Count > m_ImagesPool.Count)
                {
                    var resources = new DefaultControls.Resources();
                    var go = DefaultControls.CreateImage(resources);
                    go.layer = gameObject.layer;
                    var rt = go.transform as RectTransform;
                    if (rt)
                    {
                        rt.SetParent(rectTransform);
                        rt.localPosition = Vector3.zero;
                        rt.localRotation = Quaternion.identity;
                        rt.localScale = Vector3.one;
                    }
                    m_ImagesPool.Add(go.GetComponent<Image>());
                }
    
                var spriteName = match.Groups[1].Value;
                var size = float.Parse(match.Groups[2].Value);
                var img = m_ImagesPool[m_ImagesVertexIndex.Count - 1];
                if (img.sprite == null || img.sprite.name != spriteName)
                {
                    img.sprite = funLoadSprite != null ? funLoadSprite(spriteName) :
                        Resources.Load<Sprite>(spriteName);
                }
                img.rectTransform.sizeDelta = new Vector2(size, size);
                img.enabled = true;
            }
    
            for (var i = m_ImagesVertexIndex.Count; i < m_ImagesPool.Count; i++)
            {
                if (m_ImagesPool[i])
                {
                    m_ImagesPool[i].enabled = false;
                }
            }
        }
    
        protected override void OnPopulateMesh(VertexHelper toFill)
        {
            var orignText = m_Text;
            m_Text = m_OutputText;
            base.OnPopulateMesh(toFill);
            m_Text = orignText;
    
            UIVertex vert = new UIVertex();
            for (var i = 0; i < m_ImagesVertexIndex.Count; i++)
            {
                var endIndex = m_ImagesVertexIndex[i];
                var rt = m_ImagesPool[i].rectTransform;
                var size = rt.sizeDelta;
                if (endIndex < toFill.currentVertCount)
                {
                    toFill.PopulateUIVertex(ref vert, endIndex);
                    rt.anchoredPosition = new Vector2(vert.position.x + size.x / 2, vert.position.y + size.y / 2);
    
                    // 抹掉左下角的小黑点
                    toFill.PopulateUIVertex(ref vert, endIndex - 3);
                    var pos = vert.position;
                    for (int j = endIndex, m = endIndex - 3; j > m; j--)
                    {
                        toFill.PopulateUIVertex(ref vert, endIndex);
                        vert.position = pos;
                        toFill.SetUIVertex(vert, j);
                    }
                }
            }
    
            if (m_ImagesVertexIndex.Count != 0)
            {
                m_ImagesVertexIndex.Clear();
            }
    
            // 处理超链接包围框
            foreach (var hrefInfo in m_HrefInfos)
            {
                hrefInfo.boxes.Clear();
                if (hrefInfo.startIndex >= toFill.currentVertCount)
                {
                    continue;
                }
    
                // 将超链接里面的文本顶点索引坐标加入到包围框
                toFill.PopulateUIVertex(ref vert, hrefInfo.startIndex);
                var pos = vert.position;
                var bounds = new Bounds(pos, Vector3.zero);
                for (int i = hrefInfo.startIndex, m = hrefInfo.endIndex; i < m; i++)
                {
                    if (i >= toFill.currentVertCount)
                    {
                        break;
                    }
    
                    toFill.PopulateUIVertex(ref vert, i);
                    pos = vert.position;
                    if (pos.x < bounds.min.x) // 换行重新添加包围框
                    {
                        hrefInfo.boxes.Add(new Rect(bounds.min, bounds.size));
                        bounds = new Bounds(pos, Vector3.zero);
                    }
                    else
                    {
                        bounds.Encapsulate(pos); // 扩展包围框
                    }
                }
                hrefInfo.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=blue>");  // 超链接颜色
    
                var group = match.Groups[1];
                var hrefInfo = new HrefInfo
                {
                    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)
        {
            Vector2 lp;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                rectTransform, eventData.position, eventData.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))
                    {
                        m_OnHrefClick.Invoke(hrefInfo.name);
                        return;
                    }
                }
            }
        }
    
        /// <summary>
        /// 超链接信息类
        /// </summary>
        private class HrefInfo
        {
            public int startIndex;
            public int endIndex;
            public string name;
            public readonly List<Rect> boxes = new List<Rect>();
        }
    }
    View Code

    作者:无幻

    原文:https://blog.csdn.net/akof1314/article/details/49077983

    源码和示例地址:https://github.com/akof1314/uGUI_LinkImageText

  • 相关阅读:
    共享库的使用(.so)文件
    C/C++ 的宏中#和##的作用和展开
    有趣的打字训练
    libtool 创建库的工具
    vcpkg-微软开发的VC++打包工具
    Q他中的乱码再理解
    关于头文件和源文件的分别
    std::set 中内部元素有序条件删除的理解
    python 的 字节码 导入使用
    Pychar-20170301快捷键
  • 原文地址:https://www.cnblogs.com/Joke-crazy/p/9851907.html
Copyright © 2020-2023  润新知