RichTextImage.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. namespace textUtility
  2. {
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using textUtility;
  7. using UnityEngine;
  8. using UnityEngine.EventSystems;
  9. using UnityEngine.UI;
  10. [Serializable]
  11. public class RichTextImage : Image, IPointerClickHandler
  12. {
  13. #region Config
  14. private bool EnableOverflowClick;
  15. [SerializeField] private Button Button;
  16. [SerializeField] private RichText RichText;
  17. private List<BaseMatch> SpriteMatches = new List<BaseMatch>();
  18. private List<BaseMatch> UnderlineMatches = new List<BaseMatch>();
  19. private List<BaseMatch> SuperlinkMatches = new List<BaseMatch>();
  20. public RichTextImageManager ImageManager;
  21. private Dictionary<int, List<Vector3>> SuperlinkPositionsDictionary = new Dictionary<int, List<Vector3>>();
  22. #endregion
  23. protected override void OnPopulateMesh(VertexHelper toFill)
  24. {
  25. //Debug.Log(1);
  26. toFill.Clear();
  27. List<BaseMatch> baseMatches = new List<BaseMatch>();
  28. baseMatches.AddRange(SpriteMatches);
  29. baseMatches.AddRange(UnderlineMatches);
  30. baseMatches.AddRange(SuperlinkMatches);
  31. //Debug.Log(baseMatches.Count);
  32. List<int> triangles = new List<int>();
  33. List<UIVertex> vertices = new List<UIVertex>();
  34. foreach (var baseMatch in baseMatches)
  35. {
  36. List<List<UIVertex>> verticesList = GetRenderVerticesList(baseMatch);
  37. foreach (var tempVertices in verticesList)
  38. {
  39. triangles.AddRange(GetTriangles(vertices));
  40. vertices.AddRange(tempVertices);
  41. }
  42. }
  43. //Debug.Log(vertices.Count);
  44. //Debug.Log(triangles.Count);
  45. toFill.AddUIVertexStream(vertices, triangles);
  46. }
  47. public void AddMatch(BaseMatch baseMatch)
  48. {
  49. if (baseMatch is SpriteMatch)
  50. {
  51. SpriteMatches.Add(baseMatch);
  52. sprite = Sprite.Create((baseMatch as SpriteMatch).SpriteInfo.Sprite.texture, new Rect(), new Vector2(0.5f, 0.5f));
  53. }
  54. else if (baseMatch is UnderlineMatch)
  55. {
  56. UnderlineMatches.Add(baseMatch);
  57. }
  58. else if (baseMatch is SuperlinkMatch)
  59. {
  60. SuperlinkMatches.Add(baseMatch);
  61. if (EnableOverflowClick)
  62. {
  63. if (Button == null)
  64. {
  65. Button = gameObject.AddComponent<Button>();
  66. }
  67. Button.enabled = true;
  68. }
  69. }
  70. else
  71. {
  72. throw new Exception();
  73. }
  74. }
  75. public void ClearMatches()
  76. {
  77. SpriteMatches = new List<BaseMatch>();
  78. UnderlineMatches = new List<BaseMatch>();
  79. SuperlinkMatches = new List<BaseMatch>();
  80. SuperlinkPositionsDictionary = new Dictionary<int, List<Vector3>>();
  81. sprite = null;
  82. if (Button != null)
  83. {
  84. Button.enabled = false;
  85. }
  86. }
  87. private List<List<UIVertex>> GetRenderVerticesList(BaseMatch baseMatch)
  88. {
  89. if (baseMatch is SpriteMatch)
  90. {
  91. return GetSpriteRenderVerticesList(baseMatch);
  92. }
  93. else if (baseMatch is UnderlineMatch)
  94. {
  95. return GetUnderlineRenderVerticesList(baseMatch);
  96. }
  97. else if (baseMatch is SuperlinkMatch)
  98. {
  99. return GetSuperlinkRenderVerticesList(baseMatch);
  100. }
  101. else
  102. {
  103. throw new Exception();
  104. }
  105. }
  106. private List<List<UIVertex>> GetSpriteRenderVerticesList(BaseMatch baseMatch)
  107. {
  108. List<List<UIVertex>> verticesList = new List<List<UIVertex>>();
  109. SpriteMatch spriteMatch = (SpriteMatch) baseMatch;
  110. Vector3 middleCenter = new Vector3();
  111. float x;
  112. float y;
  113. int startIndex = spriteMatch.StartIndex;
  114. int endIndex = spriteMatch.EndIndex;
  115. if (startIndex == 0 || RichText.text[startIndex - 1] == '\n' || !RichText.IsSameLine(RichText.cachedTextGenerator, startIndex - 1, startIndex))
  116. {
  117. x = (ImageManager.Vertices[2 + endIndex*6].position.x + ImageManager.Vertices[4 + startIndex*6].position.x)/2;
  118. }
  119. else
  120. {
  121. startIndex--;
  122. x = (ImageManager.Vertices[2 + endIndex*6].position.x + ImageManager.Vertices[2 + startIndex*6].position.x)/2;
  123. }
  124. int lineIndex = RichText.GetLineIndex(RichText.cachedTextGenerator, startIndex);
  125. y = RichText.GetLineCenterY(lineIndex, RichText.cachedTextGenerator.lineCount);
  126. middleCenter.x = x;
  127. middleCenter.y = y;
  128. UIVertex upperLeft = new UIVertex();
  129. UIVertex upperRight = new UIVertex();
  130. UIVertex lowerRight = new UIVertex();
  131. UIVertex lowerLeft = new UIVertex();
  132. upperLeft.position = middleCenter + new Vector3(-spriteMatch.ScaledWidth/2, spriteMatch.ScaledHeight/2, 0);
  133. upperRight.position = middleCenter + new Vector3(spriteMatch.ScaledWidth/2, spriteMatch.ScaledHeight/2, 0);
  134. lowerRight.position = middleCenter + new Vector3(spriteMatch.ScaledWidth/2, -spriteMatch.ScaledHeight/2, 0);
  135. lowerLeft.position = middleCenter + new Vector3(-spriteMatch.ScaledWidth/2, -spriteMatch.ScaledHeight/2, 0);
  136. upperLeft.uv0 = spriteMatch.SpriteInfo.UVs[0];
  137. upperRight.uv0 = spriteMatch.SpriteInfo.UVs[1];
  138. lowerRight.uv0 = spriteMatch.SpriteInfo.UVs[2];
  139. lowerLeft.uv0 = spriteMatch.SpriteInfo.UVs[3];
  140. upperLeft.color = spriteMatch.SpriteInfo.SpriteSetting.Color;
  141. upperRight.color = spriteMatch.SpriteInfo.SpriteSetting.Color;
  142. lowerRight.color = spriteMatch.SpriteInfo.SpriteSetting.Color;
  143. lowerLeft.color = spriteMatch.SpriteInfo.SpriteSetting.Color;
  144. verticesList.Add(new List<UIVertex> {upperLeft, upperRight, lowerRight, lowerLeft});
  145. for (int i = 0; i < verticesList.Count; i++)
  146. {
  147. List<UIVertex> tempVertices = verticesList[i];
  148. Vector3 position0 = transform.TransformPoint(tempVertices[0].position);
  149. Vector3 position1 = transform.TransformPoint(tempVertices[1].position);
  150. Vector3 position2 = transform.TransformPoint(tempVertices[2].position);
  151. Vector3 position3 = transform.TransformPoint(tempVertices[3].position);
  152. Debug.DrawLine(position0, position1, Color.red, 999);
  153. Debug.DrawLine(position1, position2, Color.red, 999);
  154. Debug.DrawLine(position2, position3, Color.red, 999);
  155. Debug.DrawLine(position3, position0, Color.red, 999);
  156. }
  157. return verticesList;
  158. }
  159. private List<List<UIVertex>> GetUnderlineRenderVerticesList(BaseMatch baseMatch)
  160. {
  161. List<List<UIVertex>> verticesList = new List<List<UIVertex>>();
  162. UnderlineMatch underlineMatch = (UnderlineMatch) baseMatch;
  163. RichText.GetSegments(RichText.text, RichText.cachedTextGenerator, underlineMatch, underlineMatch.UnderlineSetting.UnderlineExcludeChars);
  164. for (int j = 0; j < underlineMatch.Segments.Count; j++)
  165. {
  166. int startIndex = underlineMatch.Segments[j][0];
  167. int endIndex = underlineMatch.Segments[j][1];
  168. int lineIndex = RichText.GetLineIndex(RichText.cachedTextGenerator, startIndex);
  169. float penPositionY = RichText.GetPenPositionY(lineIndex, RichText.cachedTextGenerator.lineCount);
  170. float charHeight = RichText.cachedTextGenerator.lines[lineIndex].height;
  171. Vector3 position0 = ImageManager.Vertices[4 + startIndex*6].position;
  172. Vector3 position1 = ImageManager.Vertices[2 + endIndex*6].position;
  173. position0.y = penPositionY;
  174. position1.y = penPositionY;
  175. Vector3 position2 = position1;
  176. Vector3 position3 = position0;
  177. position2.y -= charHeight* underlineMatch.UnderlineSetting.Scale;
  178. position3.y -= charHeight* underlineMatch.UnderlineSetting.Scale;
  179. UIVertex upperLeft = new UIVertex();
  180. UIVertex upperRight = new UIVertex();
  181. UIVertex lowerRight = new UIVertex();
  182. UIVertex lowerLeft = new UIVertex();
  183. upperLeft.position = position0;
  184. upperRight.position = position1;
  185. lowerRight.position = position2;
  186. lowerLeft.position = position3;
  187. upperLeft.color = underlineMatch.UnderlineSetting.Color;
  188. upperRight.color = underlineMatch.UnderlineSetting.Color;
  189. lowerRight.color = underlineMatch.UnderlineSetting.Color;
  190. lowerLeft.color = underlineMatch.UnderlineSetting.Color;
  191. verticesList.Add(new List<UIVertex> {upperLeft, upperRight, lowerRight, lowerLeft});
  192. position0 = transform.TransformPoint(position0);
  193. position1 = transform.TransformPoint(position1);
  194. position2 = transform.TransformPoint(position2);
  195. position3 = transform.TransformPoint(position3);
  196. Debug.DrawLine(position0, position1, Color.blue, 999);
  197. Debug.DrawLine(position1, position2, Color.blue, 999);
  198. Debug.DrawLine(position2, position3, Color.blue, 999);
  199. Debug.DrawLine(position3, position0, Color.blue, 999);
  200. }
  201. return verticesList;
  202. }
  203. private List<List<UIVertex>> GetSuperlinkRenderVerticesList(BaseMatch baseMatch)
  204. {
  205. List<List<UIVertex>> verticesList = new List<List<UIVertex>>();
  206. SuperlinkMatch superlinkMatch = (SuperlinkMatch)baseMatch;
  207. RichText.GetSegments(RichText.text, RichText.cachedTextGenerator, superlinkMatch, superlinkMatch.SuperlinkSetting.SuperlinkExcludeChars);
  208. for (int j = 0; j < superlinkMatch.Segments.Count; j++)
  209. {
  210. int startIndex = superlinkMatch.Segments[j][0];
  211. int endIndex = superlinkMatch.Segments[j][1];
  212. int lineIndex = RichText.GetLineIndex(RichText.cachedTextGenerator, startIndex);
  213. float lineCenterY = RichText.GetLineCenterY(lineIndex, RichText.cachedTextGenerator.lineCount);
  214. float lineHeight = RichText.cachedTextGenerator.lines[lineIndex].height;
  215. EnableOverflowClick = superlinkMatch.SuperlinkSetting.EnableOverflowClick;
  216. float lineMaxY = lineCenterY + (lineHeight/2)* superlinkMatch.SuperlinkSetting.Scale;
  217. float lineMinY = lineCenterY - (lineHeight/2)* superlinkMatch.SuperlinkSetting.Scale;
  218. List<Vector3> superlinkPositions = new List<Vector3>();
  219. Vector3 position0 = ImageManager.Vertices[4 + startIndex*6].position;
  220. Vector3 position1 = ImageManager.Vertices[2 + endIndex*6].position;
  221. Vector3 position2 = position1;
  222. Vector3 position3 = position0;
  223. position0.y = lineMinY;
  224. position1.y = lineMinY;
  225. position2.y = lineMaxY;
  226. position3.y = lineMaxY;
  227. superlinkPositions.Add(position0);
  228. superlinkPositions.Add(position1);
  229. superlinkPositions.Add(position2);
  230. superlinkPositions.Add(position3);
  231. SuperlinkPositionsDictionary.Add(superlinkMatch.ID, superlinkPositions);
  232. position0 = transform.TransformPoint(position0);
  233. position1 = transform.TransformPoint(position1);
  234. position2 = transform.TransformPoint(position2);
  235. position3 = transform.TransformPoint(position3);
  236. Debug.DrawLine(position0, position1, Color.green, 999);
  237. Debug.DrawLine(position1, position2, Color.green, 999);
  238. Debug.DrawLine(position2, position3, Color.green, 999);
  239. Debug.DrawLine(position3, position0, Color.green, 999);
  240. }
  241. return verticesList;
  242. }
  243. private List<int> GetTriangles(List<UIVertex> vertices)
  244. {
  245. List<int> triangles = new List<int>();
  246. triangles.Add(vertices.Count);
  247. triangles.Add(vertices.Count + 1);
  248. triangles.Add(vertices.Count + 2);
  249. triangles.Add(vertices.Count + 2);
  250. triangles.Add(vertices.Count + 3);
  251. triangles.Add(vertices.Count);
  252. return triangles;
  253. }
  254. public static RichTextImage CreateImage(RichText richText)
  255. {
  256. GameObject go = new GameObject("RichTextImage");
  257. go.transform.SetParent(richText.transform);
  258. RichTextImage image = go.AddComponent<RichTextImage>();
  259. image.RichText = richText;
  260. image.rectTransform.localPosition = Vector3.zero;
  261. image.rectTransform.localScale = Vector3.one;
  262. image.rectTransform.anchorMin = Vector2.zero;
  263. image.rectTransform.anchorMax = Vector2.one;
  264. image.rectTransform.offsetMin = Vector2.zero;
  265. image.rectTransform.offsetMax = Vector2.zero;
  266. image.rectTransform.sizeDelta = Vector2.zero;
  267. return image;
  268. }
  269. private void Update()
  270. {
  271. if (!EnableOverflowClick)
  272. {
  273. return;
  274. }
  275. if (Input.GetMouseButtonDown(0)) //Overflow的情况下检测超链接是否被点击
  276. {
  277. Graphic graphic = GetComponent<Graphic>();
  278. Graphic selectedGraphic = EventSystem.current.currentSelectedGameObject == null ? null : EventSystem.current.currentSelectedGameObject.GetComponent<Graphic>();
  279. if (selectedGraphic == null)
  280. {
  281. OnPointerClick(Input.mousePosition);
  282. }
  283. else if (graphic != selectedGraphic && graphic.depth > selectedGraphic.depth)
  284. {
  285. OnPointerClick(Input.mousePosition);
  286. }
  287. }
  288. }
  289. public void OnPointerClick(PointerEventData eventData)
  290. {
  291. //Vector3 clickPosition = eventData.position;
  292. //Debug.Log(clickPosition);
  293. OnPointerClick(eventData.position);
  294. }
  295. public void OnPointerClick(Vector3 worldPosition)
  296. {
  297. Vector3 clickPosition = rectTransform.InverseTransformPoint(worldPosition);
  298. foreach (var kv in SuperlinkPositionsDictionary)
  299. {
  300. float minX = kv.Value.MyMin(vector => vector.x).x;
  301. float maxX = kv.Value.MyMax(vector => vector.x).x;
  302. float minY = kv.Value.MyMin(vector => vector.y).y;
  303. float maxY = kv.Value.MyMax(vector => vector.y).y;
  304. //Debug.Log(clickPosition);
  305. //Debug.Log(minX + " " + maxX + " " + minY + " " + maxY);
  306. if ((minX <= clickPosition.x && clickPosition.x <= maxX) && (minY <= clickPosition.y && clickPosition.y <= maxY))
  307. {
  308. if (RichText.SuperlinkCallbackDictionary.ContainsKey(kv.Key))
  309. {
  310. RichText.SuperlinkCallbackDictionary[kv.Key].Invoke(kv.Key);
  311. }
  312. else
  313. {
  314. throw new Exception(string.Format("没有找到事件 id : {0}", kv.Key));
  315. }
  316. }
  317. }
  318. }
  319. }
  320. }