| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- 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>
- public class HyperlinkText : Text, IPointerClickHandler
- {
- /// <summary>
- /// 超链接信息类
- /// </summary>
- private class HyperlinkInfo
- {
- public int startIndex;
- public int endIndex;
- public string name;
- public readonly List<Rect> boxes = new List<Rect>();
- }
- /// <summary>
- /// 解析完最终的文本
- /// </summary>
- private string m_OutputText;
- /// <summary>
- /// 超链接信息列表
- /// </summary>
- private readonly List<HyperlinkInfo> m_HrefInfos = new List<HyperlinkInfo>();
- /// <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_HrefRegex = new Regex(@"<a href=([^>\n\s]+)>(.*?)(</a>)", RegexOptions.Singleline);
- private HyperlinkText mHyperlinkText;
- public System.Action<string> onClickCallBack;
- public string GetHyperlinkInfo
- {
- get { return text; }
- }
- protected override void Awake()
- {
- base.Awake();
- mHyperlinkText = GetComponent<HyperlinkText>();
- }
- protected override void OnEnable()
- {
- base.OnEnable();
- mHyperlinkText.onHrefClick.AddListener(OnHyperlinkTextInfo);
- }
- protected override void OnDisable()
- {
- base.OnDisable();
- mHyperlinkText.onHrefClick.RemoveListener(OnHyperlinkTextInfo);
- }
- public override void SetVerticesDirty()
- {
- base.SetVerticesDirty();
- #if UNITY_EDITOR
- if (UnityEditor.PrefabUtility.GetPrefabType(this) == UnityEditor.PrefabType.Prefab)
- {
- return;
- }
- #endif
- // m_OutputText = GetOutputText(text);
- text = GetHyperlinkInfo;
- m_OutputText = GetOutputText(text);
- }
- protected override void OnPopulateMesh(VertexHelper toFill)
- {
- var orignText = m_Text;
- m_Text = m_OutputText;
- base.OnPopulateMesh(toFill);
- m_Text = orignText;
- UIVertex vert = new UIVertex();
- // 处理超链接包围框
- 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));
-
- var group = match.Groups[1];
- var hrefInfo = new HyperlinkInfo
- {
- startIndex = s_TextBuilder.Length * 4, // 超链接里的文本起始顶点索引
- endIndex = (s_TextBuilder.Length + match.Groups[2].Length - 1) * 4 + 3,
- name = group.Value
- };
- s_TextBuilder.Append("<b><color=#CC5B13>"); // 超链接颜色
- m_HrefInfos.Add(hrefInfo);
- s_TextBuilder.Append(match.Groups[2].Value);
- s_TextBuilder.Append("</color></b>");
- 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 = Vector2.zero;
- 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>
- /// <param name="info">回调信息</param>
- private void OnHyperlinkTextInfo(string info)
- {
- onClickCallBack?.Invoke(info);
- // Debug.Log("超链接信息:" + info);
- }
- }
|