miduo_client/Assets/LuaFramework/Scripts/OwnTools/InLine/InlineText.cs

402 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/// ========================================================
/// fileInlineText.cs
/// brief
/// author coding2233
/// date
/// versionv1.0
/// ========================================================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Text.RegularExpressions;
using System.Text;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using System;
[ExecuteInEditMode]
public class InlineText : Text, IPointerClickHandler
{
// 用正则取 [图集ID#表情Tag] ID值==-1 ,表示为超链接
private static readonly Regex _InputTagRegex = new Regex(@"\[(\-{0,1}\d{0,})#(.+?)\]", RegexOptions.Singleline);
//文本表情管理器
private InlineManager _InlineManager;
//更新后的文本
private string _OutputText = "";
//表情位置索引信息
Dictionary<int, SpriteTagInfo> _SpriteInfo = new Dictionary<int, SpriteTagInfo>();
//图集ID相关信息
Dictionary<int, List<SpriteTagInfo>> _DrawSpriteInfo = new Dictionary<int, List<SpriteTagInfo>>();
#region 超链接
[System.Serializable]
public class HrefClickEvent : UnityEvent<string> { }
//点击事件监听
public HrefClickEvent OnHrefClick = new HrefClickEvent();
// 超链接信息列表
private readonly List<HrefInfo> _ListHrefInfos = new List<HrefInfo>();
#endregion
/// <summary>
/// 初始化
/// </summary>
protected override void OnEnable()
{
//
base.OnEnable();
//支持富文本
supportRichText = true;
//对齐几何
alignByGeometry = true;
if (!_InlineManager)
_InlineManager = GetComponentInParent<InlineManager>();
//启动的是 更新顶点
SetVerticesDirty();
}
public void ActiveText()
{
OnEnable();
}
public override void SetVerticesDirty()
{
base.SetVerticesDirty();
if (!_InlineManager)
{
_OutputText = m_Text;
return;
}
//设置新文本
_OutputText = GetOutputText();
}
readonly UIVertex[] m_TempVerts = new UIVertex[4];
protected override void OnPopulateMesh(VertexHelper toFill)
{
if (font == null)
return;
// We don't care if we the font Texture changes while we are doing our Update.
// The end result of cachedTextGenerator will be valid for this instance.
// Otherwise we can get issues like Case 619238.
m_DisableFontTextureRebuiltCallback = true;
Vector2 extents = rectTransform.rect.size;
var settings = GetGenerationSettings(extents);
// cachedTextGenerator.PopulateWithErrors(text, settings, gameObject);
cachedTextGenerator.Populate(_OutputText, settings);
// Apply the offset to the vertices
IList<UIVertex> verts = cachedTextGenerator.verts;
float unitsPerPixel = 1 / pixelsPerUnit;
//Last 4 verts are always a new line... (\n)
int vertCount = verts.Count - 4;
Vector2 roundingOffset = new Vector2(verts[0].position.x, verts[0].position.y) * unitsPerPixel;
roundingOffset = PixelAdjustPoint(roundingOffset) - roundingOffset;
toFill.Clear();
//计算quad占位的信息
CalcQuadInfo(verts);
//计算包围盒
CalcBoundsInfo(verts,toFill,settings);
if (roundingOffset != Vector2.zero)
{
for (int i = 0; i < vertCount; ++i)
{
int tempVertsIndex = i & 3;
m_TempVerts[tempVertsIndex] = verts[i];
m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
m_TempVerts[tempVertsIndex].position.x += roundingOffset.x;
m_TempVerts[tempVertsIndex].position.y += roundingOffset.y;
if (tempVertsIndex == 3)
toFill.AddUIVertexQuad(m_TempVerts);
}
}
else
{
for (int i = 0; i < vertCount; ++i)
{
int tempVertsIndex = i & 3;
m_TempVerts[tempVertsIndex] = verts[i];
m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
if (tempVertsIndex == 3)
toFill.AddUIVertexQuad(m_TempVerts);
}
}
m_DisableFontTextureRebuiltCallback = false;
}
#region 文本所占的长宽
public override float preferredWidth
{
get
{
var settings = GetGenerationSettings(Vector2.zero);
return cachedTextGeneratorForLayout.GetPreferredWidth(_OutputText, settings) / pixelsPerUnit;
}
}
public override float preferredHeight
{
get
{
var settings = GetGenerationSettings(new Vector2(rectTransform.rect.size.x, 0.0f));
return cachedTextGeneratorForLayout.GetPreferredHeight(_OutputText, settings) / pixelsPerUnit;
}
}
#endregion
#region 计算Quad占位信息
void CalcQuadInfo(IList<UIVertex> verts)
{
foreach (var item in _SpriteInfo)
{
if ((item.Key + 4) > verts.Count)
continue;
for (int i = item.Key; i < item.Key + 4; i++)
{
//清除乱码
UIVertex tempVertex = verts[i];
tempVertex.uv0 = Vector2.zero;
verts[i] = tempVertex;
//计算位置
item.Value._Pos[i - item.Key] = tempVertex.position;
}
}
//绘制表情
UpdateDrawnSprite();
}
#endregion
#region 绘制表情
void UpdateDrawnSprite()
{
_DrawSpriteInfo = new Dictionary<int, List<SpriteTagInfo>>();
foreach (var item in _SpriteInfo)
{
int _id = item.Value._ID;
string _tag = item.Value._Tag;
//更新绘制表情的信息
List<SpriteTagInfo> _listSpriteInfo = null;
if (_DrawSpriteInfo.ContainsKey(_id))
_listSpriteInfo = _DrawSpriteInfo[_id];
else
{
_listSpriteInfo = new List<SpriteTagInfo>();
_DrawSpriteInfo.Add(_id, _listSpriteInfo);
}
_listSpriteInfo.Add(item.Value);
}
foreach (var item in _DrawSpriteInfo)
{
_InlineManager.UpdateTextInfo(item.Key, this, item.Value);
}
}
#endregion
#region 处理超链接的包围盒
void CalcBoundsInfo(IList<UIVertex> verts, VertexHelper toFill,TextGenerationSettings settings)
{
#region 包围框
// 处理超链接包围框
UIVertex vert = new UIVertex();
foreach (var hrefInfo in _ListHrefInfos)
{
hrefInfo.boxes.Clear();
if (hrefInfo.startIndex >= verts.Count)
{
continue;
}
// 将超链接里面的文本顶点索引坐标加入到包围框
vert = verts[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 >= verts.Count)
{
break;
}
vert = verts[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));
}
#endregion
#region 添加下划线
TextGenerator _UnderlineText = new TextGenerator();
_UnderlineText.Populate("_", settings);
IList<UIVertex> _TUT = _UnderlineText.verts;
foreach (var item in _ListHrefInfos)
{
for (int i = 0; i < item.boxes.Count; i++)
{
//计算下划线的位置
Vector3[] _ulPos = new Vector3[4];
_ulPos[0] = item.boxes[i].position + new Vector2(0.0f, fontSize * 0.2f);
_ulPos[1] = _ulPos[0]+new Vector3(item.boxes[i].width,0.0f);
_ulPos[2] = item.boxes[i].position + new Vector2(item.boxes[i].width, 0.0f);
_ulPos[3] =item.boxes[i].position;
//绘制下划线
for (int j = 0; j < 4; j++)
{
m_TempVerts[j] = _TUT[j];
m_TempVerts[j].color = Color.blue;
m_TempVerts[j].position = _ulPos[j];
if (j == 3)
toFill.AddUIVertexQuad(m_TempVerts);
}
}
}
#endregion
}
#endregion
#region 根据正则规则更新文本
private string GetOutputText()
{
_SpriteInfo = new Dictionary<int, SpriteTagInfo>();
StringBuilder _textBuilder = new StringBuilder();
int _textIndex = 0;
foreach (Match match in _InputTagRegex.Matches(text))
{
int _tempID = 0;
if (!string.IsNullOrEmpty(match.Groups[1].Value))
_tempID = int.Parse(match.Groups[1].Value);
string _tempTag = match.Groups[2].Value;
//更新超链接
if (_tempID == -1)
{
_textBuilder.Append(text.Substring(_textIndex, match.Index - _textIndex));
_textBuilder.Append("<color=blue>");
int _startIndex = _textBuilder.Length * 4;
_textBuilder.Append("[" + match.Groups[2].Value + "]");
int _endIndex = _textBuilder.Length * 4 - 2;
_textBuilder.Append("</color>");
var hrefInfo = new HrefInfo
{
startIndex = _startIndex, // 超链接里的文本起始顶点索引
endIndex = _endIndex,
name = match.Groups[2].Value
};
_ListHrefInfos.Add(hrefInfo);
}
//更新表情
else
{
if (!_InlineManager._IndexSpriteInfo.ContainsKey(_tempID)
|| !_InlineManager._IndexSpriteInfo[_tempID].ContainsKey(_tempTag))
continue;
SpriteInforGroup _tempGroup = _InlineManager._IndexSpriteInfo[_tempID][_tempTag];
_textBuilder.Append(text.Substring(_textIndex, match.Index - _textIndex));
int _tempIndex = _textBuilder.Length * 4;
_textBuilder.Append(@"<quad size=" + _tempGroup.size + " width=" + _tempGroup.width + " />");
SpriteTagInfo _tempSpriteTag = new SpriteTagInfo
{
_ID = _tempID,
_Tag = _tempTag,
_Size = new Vector2(_tempGroup.size * _tempGroup.width, _tempGroup.size),
_Pos = new Vector3[4],
_UV = _tempGroup.listSpriteInfor[0].uv
};
if (!_SpriteInfo.ContainsKey(_tempIndex))
_SpriteInfo.Add(_tempIndex, _tempSpriteTag);
}
_textIndex = match.Index + match.Length;
}
_textBuilder.Append(text.Substring(_textIndex, text.Length - _textIndex));
return _textBuilder.ToString();
}
#endregion
#region 超链接信息类
private class HrefInfo
{
public int startIndex;
public int endIndex;
public string name;
public readonly List<Rect> boxes = new List<Rect>();
}
#endregion
#region 点击事件检测是否点击到超链接文本
public void OnPointerClick(PointerEventData eventData)
{
Vector2 lp;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
rectTransform, eventData.position, eventData.pressEventCamera, out lp);
foreach (var hrefInfo in _ListHrefInfos)
{
var boxes = hrefInfo.boxes;
for (var i = 0; i < boxes.Count; ++i)
{
if (boxes[i].Contains(lp))
{
OnHrefClick.Invoke(hrefInfo.name);
return;
}
}
}
}
#endregion
}
public class SpriteTagInfo
{
//图集ID
public int _ID;
//标签标签
public string _Tag;
//标签大小
public Vector2 _Size;
//表情位置
public Vector3[] _Pos;
//uv
public Vector2[] _UV;
}