From 62017488d94dbc7a06311df1a94f68411bd6b4b0 Mon Sep 17 00:00:00 2001 From: zhangjiannan Date: Mon, 21 Oct 2024 19:25:57 +0800 Subject: [PATCH] 1 --- .../Prefabs/UI/Login/LoginPanel.prefab | 11 +- Assets/Scripts/UI/HyperlinkText.cs | 223 ++++++++++++++++++ Assets/Scripts/UI/HyperlinkText.cs.meta | 11 + 3 files changed, 241 insertions(+), 4 deletions(-) create mode 100644 Assets/Scripts/UI/HyperlinkText.cs create mode 100644 Assets/Scripts/UI/HyperlinkText.cs.meta diff --git a/Assets/ManagedResources/Prefabs/UI/Login/LoginPanel.prefab b/Assets/ManagedResources/Prefabs/UI/Login/LoginPanel.prefab index 0e44f7470..b4b1573bc 100644 --- a/Assets/ManagedResources/Prefabs/UI/Login/LoginPanel.prefab +++ b/Assets/ManagedResources/Prefabs/UI/Login/LoginPanel.prefab @@ -2704,7 +2704,7 @@ GameObject: m_Component: - component: {fileID: 7533799007912338597} - component: {fileID: 6381816930569376757} - - component: {fileID: 2582135536540214597} + - component: {fileID: 7980622557117263859} m_Layer: 5 m_Name: EditionDepartment m_TagString: Untagged @@ -2739,7 +2739,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 3722243489848456597} m_CullTransparentMesh: 0 ---- !u!114 &2582135536540214597 +--- !u!114 &7980622557117263859 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -2748,7 +2748,7 @@ MonoBehaviour: m_GameObject: {fileID: 3722243489848456597} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Script: {fileID: 11500000, guid: ba0767c299248ba4bbfec58f82dcc490, type: 3} m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} @@ -2762,7 +2762,7 @@ MonoBehaviour: m_FontSize: 22 m_FontStyle: 0 m_BestFit: 0 - m_MinSize: 0 + m_MinSize: 2 m_MaxSize: 40 m_Alignment: 4 m_AlignByGeometry: 0 @@ -2771,6 +2771,9 @@ MonoBehaviour: m_VerticalOverflow: 0 m_LineSpacing: 1 m_Text: + m_OnHrefClick: + m_PersistentCalls: + m_Calls: [] --- !u!1 &3879604362564083972 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/UI/HyperlinkText.cs b/Assets/Scripts/UI/HyperlinkText.cs new file mode 100644 index 000000000..b9098a30d --- /dev/null +++ b/Assets/Scripts/UI/HyperlinkText.cs @@ -0,0 +1,223 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +/// +/// 文本控件,支持超链接 +/// +public class HyperlinkText : Text, IPointerClickHandler +{ + /// + /// 超链接信息类 + /// + private class HyperlinkInfo + { + public int startIndex; + + public int endIndex; + + public string name; + + public readonly List boxes = new List(); + } + + /// + /// 解析完最终的文本 + /// + private string m_OutputText; + + /// + /// 超链接信息列表 + /// + private readonly List m_HrefInfos = new List(); + + /// + /// 文本构造器 + /// + protected static readonly StringBuilder s_TextBuilder = new StringBuilder(); + + [Serializable] + public class HrefClickEvent : UnityEvent { } + + [SerializeField] + private HrefClickEvent m_OnHrefClick = new HrefClickEvent(); + + /// + /// 超链接点击事件 + /// + public HrefClickEvent onHrefClick + { + get { return m_OnHrefClick; } + set { m_OnHrefClick = value; } + } + + + /// + /// 超链接正则 + /// + private static readonly Regex s_HrefRegex = new Regex(@"\n\s]+)>(.*?)()", RegexOptions.Singleline); + + private HyperlinkText mHyperlinkText; + + protected override void Awake() + { + base.Awake(); + mHyperlinkText = GetComponent(); + } + 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); + + } + + + 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)); + } + } + + /// + /// 获取超链接解析后的最后输出文本 + /// + /// + 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)); + + string str = s_TextBuilder.ToString(); + char[] array = str.ToCharArray(); //把字符串转化成字符数组 + IEnumerator enumerator = array.GetEnumerator(); //得到枚举器 + StringBuilder stringBuilder = new StringBuilder(); + while (enumerator.MoveNext()) //开始枚举 + { + if ((char)enumerator.Current != ' ') //向StringBuilder类对象添加非空格字符 + stringBuilder.Append(enumerator.Current.ToString()); + } + + var group = match.Groups[1]; + var hrefInfo = new HyperlinkInfo + { + startIndex = stringBuilder.Length * 4, // 超链接里的文本起始顶点索引 + endIndex = (stringBuilder.Length + match.Groups[2].Length - 1) * 4 + 3, + name = group.Value + }; + m_HrefInfos.Add(hrefInfo); + s_TextBuilder.Append(""); // 超链接颜色 + s_TextBuilder.Append(match.Groups[2].Value); + s_TextBuilder.Append(""); + indexText = match.Index + match.Length; + } + s_TextBuilder.Append(outputText.Substring(indexText, outputText.Length - indexText)); + return s_TextBuilder.ToString(); + } + + /// + /// 点击事件检测是否点击到超链接文本 + /// + /// + 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); + Debug.Log("sssssssssssssssssssss"); + return; + } + } + } + } + /// + /// 当前点击超链接回调 + /// + /// 回调信息 + private void OnHyperlinkTextInfo(string info) + { + Debug.Log("超链接信息:" + info); + Application.OpenURL(info); + } +} + diff --git a/Assets/Scripts/UI/HyperlinkText.cs.meta b/Assets/Scripts/UI/HyperlinkText.cs.meta new file mode 100644 index 000000000..492d317cf --- /dev/null +++ b/Assets/Scripts/UI/HyperlinkText.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba0767c299248ba4bbfec58f82dcc490 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: