推荐阅读
- CSDN主页
- GitHub开源地址
- Unity3D插件分享
- 简书地址
- 我的个人博客
大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。
一、前言
在开发中遇到了要给Text加超链接的需求,研究了实现方式,将代码和使用方法总结出来,分享一下。
二、正文
2-1、实现思路
主要有两种实现思路,一种是使用Text Mesh Pro
,可以直接加入超链接,实现点击事件。
另一种,就是继承Text脚本组件,重载OnPopulateMesh
方法,替换最终绘制的文本。
接下来就分别讲解如何使用。
2-2、继承Text脚本组件,重载OnPopulateMesh
方法
让Text显示超链接的文本内容需要以下几步:
(1)使用正则表达式提取超链接标签及里面的内容,并保存顶点信息(点击的时候使用)
(2)将文本内容加上颜色进行标识
(3)设置监听事件,在点击的时候调用
正则表达式:
//提取以<a link=>开头,以</a>结束的内容。
<a link=([^>\n\s]+)>(.*?)(</a>)
整体代码如下:
新建一个脚本命名为HyperlinkText.cs
:
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;/// <summary>
/// 超链接信息类
/// </summary>
///
[Serializable]
public class HyperlinkInfo
{public int startIndex;public int endIndex;public string name;public readonly List<Rect> boxes = new List<Rect>();
}
/// <summary>
/// 文本控件,支持超链接
/// </summary>
public class HyperlinkText : Text, IPointerClickHandler
{/// <summary>/// 解析完最终的文本/// </summary>private string m_OutputText;/// <summary>/// 超链接信息列表/// </summary>private readonly List<HyperlinkInfo> _mLinkInfos = new List<HyperlinkInfo>();/// <summary>/// 文本构造器/// </summary>protected static readonly StringBuilder s_TextBuilder = new StringBuilder();/// <summary>/// 超链接正则表达式/// </summary>private static readonly Regex s_HrefRegex = new Regex(@"<a link=([^>\n\s]+)>(.*?)(</a>)", RegexOptions.Singleline);/// <summary>/// 文本超链接控件/// </summary>private HyperlinkText mHyperlinkText;protected override void Awake(){base.Awake();mHyperlinkText = GetComponent<HyperlinkText>();}#region 回调事件public Action<string> onLinkClick;/// <summary>/// 点击事件检测是否点击到超链接文本/// </summary>/// <param name="eventData"></param>public void OnPointerClick(PointerEventData eventData){RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out var lp);foreach (var info in _mLinkInfos){var boxes = info.boxes;for (var i = 0; i < boxes.Count; ++i){if (!boxes[i].Contains(lp)) continue;onLinkClick?.Invoke(info.name);return;}}}#endregion#region 生成超链接/// <summary>/// 重新渲染网格/// </summary>public override void SetVerticesDirty(){base.SetVerticesDirty();m_OutputText = GetOutputText(text);}/// <summary>/// 处理Text顶点数据/// </summary>/// <param name="toFill"></param>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 _mLinkInfos){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;_mLinkInfos.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};_mLinkInfos.Add(hrefInfo);s_TextBuilder.Append("<color=blue>"); // 超链接颜色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();}#endregion
}
调用如下
,新建脚本命名为HyperlinkLogic.cs
,双击编辑代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class HyperlinkLogic : MonoBehaviour
{public HyperlinkText hyperlinkText;void Start(){// 动态显示文本hyperlinkText.text = "文本测试:<a link=https://blog.csdn.net/q764424567>[恬静的小魔龙]</a>";// 绑定事件hyperlinkText.onLinkClick = (info) => onclick(info);}void onclick(string info){Debug.Log(info);Application.OpenURL(info);}
}
运行结果:
2-3、使用Text Mesh Pro
加入超链接
使用Text Mesh Pro
就方便了,因为TMP自身支持超链接,只要使用标签link即可。
标签:
<link="id_01"></link>//超链接
<#0C86BA></color>//颜色
<u></u>//下划线
演示文本:
<link="id_01"><u><#0C86BA>Insert link text here</u></color></link>
新建脚本命名为TMPLink.cs
,双击编辑代码:
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;public class TMPLink : MonoBehaviour, IPointerClickHandler
{private TextMeshProUGUI m_TextMeshPro;void Awake(){m_TextMeshPro = gameObject.GetComponent<TextMeshProUGUI>();}void Start(){}public void OnPointerClick(PointerEventData eventData){int linkIndex = TMP_TextUtilities.FindIntersectingLink(m_TextMeshPro, Input.mousePosition, eventData.pressEventCamera);TMP_LinkInfo linkInfo = m_TextMeshPro.textInfo.linkInfo[linkIndex];RectTransformUtility.ScreenPointToLocalPointInRectangle(m_TextMeshPro.rectTransform, eventData.position, eventData.pressEventCamera, out var worldPointInRectangle);switch (linkInfo.GetLinkID()){case "id_01":Debug.Log("点击了id:id_01的超链接");Application.OpenURL("https://blog.csdn.net/q764424567");break;}}
}
运行点击结果:
三、后记
如果觉得本篇文章有用别忘了点个关注,关注不迷路,持续分享更多Unity干货文章。
你的点赞就是对博主的支持,有问题记得留言:
博主主页有联系方式。
博主还有跟多宝藏文章等待你的发掘哦:
专栏 | 方向 | 简介 |
---|---|---|
Unity3D开发小游戏 | 小游戏开发教程 | 分享一些使用Unity3D引擎开发的小游戏,分享一些制作小游戏的教程。 |
Unity3D从入门到进阶 | 入门 | 从自学Unity中获取灵感,总结从零开始学习Unity的路线,有C#和Unity的知识。 |
Unity3D之UGUI | UGUI | Unity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。 |
Unity3D之读取数据 | 文件读取 | 使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。 |
Unity3D之数据集合 | 数据集合 | 数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。 |
Unity3D之VR/AR(虚拟仿真)开发 | 虚拟仿真 | 总结博主工作常见的虚拟仿真需求进行案例讲解。 |
Unity3D之插件 | 插件 | 主要分享在Unity开发中用到的一些插件使用方法,插件介绍等 |
Unity3D之日常开发 | 日常记录 | 主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等 |
Unity3D之日常BUG | 日常记录 | 记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。 |