UnityのTextMeshProでサポートしているタグは
開始終了のタグ自体を含めて128バイトのバッファで解析を管理されているようで、
例えばLinkタグで長いURLを扱おうとするとパースが途中で終了して
表示がおかしくなってしまう。
これは以下のようにURLを短縮して対策できる。
- ITextPreprocessor継承クラスで、元のテキストを変換できる
- URLをRegexで拾って、元のテキスト内のURLに対して短い文字列で変換をかけつつ辞書を作る
- Clickイベント発火時にLinkInfo.GetLinkIDと比較して元の値を取得する
ITextPreprocessor継承クラスで、元のテキストを変換
ITextPreprocessorは、対象のTextMeshProGUIのテキストが更新された時に、
元のテキストを受け取って変換したテキストを返却することができる。
private class TextPreprocessor : ITextPreprocessor
{
public string PreprocessText(string text)
{
return text;
}
}
TextMeshProUGUI m_TextMeshProGUI;
TextPreprocessor m_TextPreprocessor = new TextPreprocessor();
if (TryGetComponent(out var m_TextMeshProGUI)){
m_TextMeshProGUI.textPreprocessor = m_TextPreprocessor;
}
URLをRegexで拾って、元のテキスト内のURLに対して短い文字列で変換をかけつつ辞書を作る
元のテキスト内のURLテキストを正規表現で検出し、
短い文字列と入れ替えながら、それをキーとした辞書を作成する。
private class TextPreprocessor : ITextPreprocessor
{
private const string UrlRegexPattern = @"https?://[\w!\?/\+\-_~=;\.,\*&@#\$%\(\)'\[\]]+";
public Dictionary<string, string> ShortenUrlMap { get; private set; } = new();
public string PreprocessText(string text)
{
ShortenUrlMap.Clear();
var matches = Regex.Matches(text, UrlRegexPattern);
foreach (var match in matches.Select(x => x.Value).Distinct())
{
var key = $"{ShortenUrlMap.Count}";
text = text.Replace(match, key);
ShortenUrlMap.Add(key, match);
}
return text;
}
}
Clickイベント発火時にLinkInfo.GetLinkIDと比較して元の値を取得する
上記で変換されたキーはそのままLinkIDとして入っているので、
作成済みの辞書から元の値を取得する。
// IPointerClickHandler継承クラスで、Linkタグ部分へのクリック判定をする場合
public void OnPointerClick(PointerEventData e)
{
var linkInfos = m_TextMeshProGUI.textInfo.linkInfo;
if (linkInfos.Length <= 0)
{
return;
}
var index = TMP_TextUtilities.FindIntersectingLink(m_TextMeshProGUI, e.position, e.pressEventCamera);
if (index < 0)
{
return;
}
var linkInfo = linkInfos[index];
var linkId = linkInfo.GetLinkID();
if (m_TextPreprocessor.ShortenUrlMap.TryGetValue(linkId, out var url))
{
Application.OpenURL(url);
}
}