HyperLinkText

using System;
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<Rect> boxes = new List<Rect>();

public List<int> linefeedIndexList = new List<int>();
}

private Action<string, Vector3> hyperLinkClick;
private string m_OutputText;
private readonly List<HyperLinkInfo> m_HrefInfos = new List<HyperLinkInfo>();
protected StringBuilder s_TextBuilder = new StringBuilder();

public Color32 ? UnderLineColor
{
set;
get;
}

public Color32 ? UnderLineCharacterColor
{
set;
get;
}

public void RegisterFunction(Action<string, Vector3> callBack)
{
hyperLinkClick = callBack;
}

private static readonly Regex s_HrefRegex = new Regex(@"<link=([^>\n\s]+)>(.*?)(</link>)", RegexOptions.Singleline);

private static readonly Regex s_ColorPrefixRegex = new Regex(@"<color=#([^>\n\s]+)>", RegexOptions.Singleline);

private static readonly Regex s_ColorSuffixRegex = new Regex(@"</color>", RegexOptions.Singleline);


public string GetHyperlinkInfo
{
get { return text; }
}

public override void SetVerticesDirty()
{
base.SetVerticesDirty();

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();
hrefInfo.linefeedIndexList.Clear();
if (hrefInfo.startIndex >= toFill.currentVertCount)
{
continue;
}

// 将超链接里面的文本顶点索引坐标加入到包围框
toFill.PopulateUIVertex(ref vert, hrefInfo.startIndex);

var pos = vert.position;
var bounds = new Bounds(pos, Vector3.zero);
hrefInfo.linefeedIndexList.Add(hrefInfo.startIndex);
for (int i = hrefInfo.startIndex, m = hrefInfo.endIndex; i < m; i++)
{
if (i >= toFill.currentVertCount)
{
break;
}

toFill.PopulateUIVertex(ref vert, i);
if (UnderLineCharacterColor != null) vert.color = (Color32)UnderLineCharacterColor;
toFill.SetUIVertex(vert, i);

pos = vert.position;

bool needEncapsulate = true;

if (i > 4 && (i - hrefInfo.startIndex) % 4 == 0)
{
UIVertex lastV = new UIVertex();
toFill.PopulateUIVertex(ref lastV, i - 4);
var lastPos = lastV.position;

if (pos.x < lastPos.x && pos.y < lastPos.y) // 换行重新添加包围框
{
hrefInfo.boxes.Add(new Rect(bounds.min, bounds.size));
hrefInfo.linefeedIndexList.Add(i);
bounds = new Bounds(pos, Vector3.zero);
needEncapsulate = false;
}
}
if (needEncapsulate)
{
bounds.Encapsulate(pos); // 扩展包围框
}
}
hrefInfo.boxes.Add(new Rect(bounds.min, bounds.size));
}

DrawUnderLine(toFill);

}


private void DrawUnderLine(VertexHelper vh)
{
UIVertex vert = new UIVertex();
List<Vector3> startPosList = new List<Vector3>();
List<Vector3> endPosList = new List<Vector3>();
foreach (var hrefInfo in m_HrefInfos)
{
if (hrefInfo.startIndex >= vh.currentVertCount)
{
continue;
}

float minY = float.MaxValue;
for (int i = hrefInfo.startIndex, m = hrefInfo.endIndex; i < m; i += 4)
{
if (i >= vh.currentVertCount)
{
break;
}

if (hrefInfo.linefeedIndexList.Contains(i))
{
for (int j = 0; j < startPosList.Count; j++)
{
MeshUnderLine(vh, new Vector2(startPosList[j].x, minY), new Vector2(endPosList[j].x, minY));
}
startPosList.Clear();
endPosList.Clear();
}

vh.PopulateUIVertex(ref vert, i + 3);
startPosList.Add(vert.position);
vh.PopulateUIVertex(ref vert, i + 2);
endPosList.Add(vert.position);

if (vert.position.y < minY)
{
minY = vert.position.y;
}
}

for (int j = 0; j < startPosList.Count; j++)
{
MeshUnderLine(vh, new Vector2(startPosList[j].x, minY), new Vector2(endPosList[j].x, minY));
}
startPosList.Clear();
endPosList.Clear();

}
}

private void MeshUnderLine(VertexHelper vh, Vector2 startPos, Vector2 endPos)
{
Vector2 extents = rectTransform.rect.size;
var setting = GetGenerationSettings(extents);
setting.fontSize = 35;
setting.updateBounds = true;

TextGenerator underlineText = new TextGenerator();
bool suc = underlineText.Populate("—", setting);

IList<UIVertex> lineVer = underlineText.verts;/*new UIVertex[4];*///"_"的的顶点数组

if (lineVer.Count < 4) return;

Vector3[] pos = new Vector3[4];
pos[0] = startPos + new Vector2(-1f, 0);
pos[3] = startPos + new Vector2(-1f, 4f);
pos[2] = endPos + new Vector2(1f, 4f);
pos[1] = endPos + new Vector2(1f, 0);


UIVertex[] tempVerts = new UIVertex[4];
for (int i = 0; i < 4; i++)
{
tempVerts[i] = lineVer[i];
if(UnderLineColor != null) tempVerts[i].color = (Color32)UnderLineColor;
tempVerts[i].position = pos[i];
}

vh.AddUIVertexQuad(tempVerts);
}


protected virtual string GetOutputText(string outputText)
{
s_TextBuilder.Length = 0;
m_HrefInfos.Clear();
var indexText = 0;
int count = 0;
foreach (Match match in s_HrefRegex.Matches(outputText))
{
string appendStr = outputText.Substring(indexText, match.Index - indexText);

s_TextBuilder.Append(appendStr);

// 如果appendStr 里存在color 去掉 color 的长度

int prefixCount = 0;
int suffixCount = 0;

foreach (Match prefix in s_ColorPrefixRegex.Matches(appendStr))
{
if (prefix.Index > 0) prefixCount += 1;
}

foreach (Match suffix in s_ColorSuffixRegex.Matches(appendStr))
{
if (suffix.Index > 0) suffixCount += 1;
}


count += appendStr.Length - appendStr.Replace(" ", "").Replace("\n", "").Length + prefixCount * 15 + suffixCount * 8;

int startIndex = (s_TextBuilder.Length - count) * 4;

// 如果link 内部嵌套有color

var group = match.Groups[1];

int innerPrefixCount = 0;
int innerSuffixCount = 0;

foreach (Match prefix in s_ColorPrefixRegex.Matches(match.Groups[2].ToString()))
{
if (prefix.Index > 0) innerPrefixCount += 1;
}

foreach (Match suffix in s_ColorSuffixRegex.Matches(match.Groups[2].ToString()))
{
if (suffix.Index > 0) innerSuffixCount += 1;
}

count = match.Groups[2].ToString().Length - match.Groups[2].ToString().Replace(" ", "").Replace("\n", "").Length + innerPrefixCount * 15 + innerSuffixCount * 8;
int length = match.Groups[2].ToString().Length - count;

var hrefInfo = new HyperLinkInfo
{
startIndex = startIndex, // 超链接里的文本起始顶点索引
endIndex = startIndex + (length * 4),
name = group.Value
};
m_HrefInfos.Add(hrefInfo);

s_TextBuilder.Append(match.Groups[2].Value);
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 (lp.x >= boxes[i].xMin && lp.x <= boxes[i].xMax && lp.y >= boxes[i].yMin && lp.y <= boxes[i].yMax)
{
if (hyperLinkClick != null)
{
Vector3 pos = rectTransform.TransformPoint(lp);
hyperLinkClick.Invoke(hrefInfo.name, pos);
}
return;
}

}
}
}

}

 

private void LinkClick(string linkContent, Vector3 pos)
{
CommonSkillTipsData data = new CommonSkillTipsData();
data.position = pos;
data.skillId = linkContent;
GameEntry.UI.OpenUIForm(UIFormId.CommonSkillTipsPanel, data);
}

 

 

protected override void OnOpen(object userData)
{
base.OnOpen(userData);
CommonSkillTipsData data = userData as CommonSkillTipsData;
int skillId = System.Convert.ToInt32(data.skillId);
Vector3 pos = data.position;
DRskill config = PrototypeModule.Instance.GetRowById<DRskill>(skillId);
SetContent(config);
AddButtonClick(bg_Click, () =>
{
GameEntry.UI.CloseUIForm(this);
});

var parent = CachedTransform.parent;
var rect = parent.GetComponent<RectTransform>();
var anchoredPos = GameUtils.WorldPointToUI(pos, rect);

var popRect = CachedTransform.transform as RectTransform;
var tips_bg_rect = this.tips_bg.GetComponent<RectTransform>();

var h = (tips_bg_rect.sizeDelta.y + 108) / 2;
var w = tips_bg_rect.sizeDelta.x / 2;

anchoredPos = new Vector3(anchoredPos.x + w, anchoredPos.y - h, 0);

popRect.localPosition = anchoredPos;
}

 

public static Vector2 WorldPointToUI(Vector3 point, RectTransform rectTransform)
{
Vector2 uipos = Vector2.one;

Vector2 pos = RectTransformUtility.WorldToScreenPoint(m_2DUICamera, point);

RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, pos, m_2DUICamera, out uipos);
return uipos;
}

posted @ 2023-06-16 20:34  GamesClient  阅读(32)  评论(0)    收藏  举报