[UGUI]图文混排(四):插入图片

参考链接:

http://www.cnblogs.com/leoin2012/p/7162099.html

0.图片标签和图片类

标签格式:<icon name=*** w=1 h=1 n=*** p=***/>

RichTextImageInfo.cs

 1 using UnityEngine;
 2 
 3 public class RichTextImageInfo
 4 {
 5     public string name;       //名字(路径)
 6     public Vector2 size;      //宽高
 7     public Vector2 position;  //位置
 8     public int startVertex;   //起始顶点
 9     public int vertexLength;  //占据顶点数
10     public Color color;       //颜色
11 
12     //标签属性
13     public float widthScale = 1f;//宽度缩放
14     public float heightScale = 1f;//高度缩放
15     public string eventName;//事件名
16     public string eventParameter;//事件参数
17 
18     public void SetValue(string key, string value)
19     {
20         switch (key)
21         {
22             case "w":
23                 {
24                     float.TryParse(value, out widthScale);
25                     break;
26                 }
27             case "h":
28                 {
29                     float.TryParse(value, out heightScale);
30                     break;
31                 }
32             case "n":
33                 {
34                     eventName = value;
35                     break;
36                 }
37             case "p":
38                 {
39                     eventParameter = value;
40                     break;
41                 }
42             default:
43                 break;
44         }
45     }
46 }

1.用空格替换图片标签

a.选择空格符

换行空格:Space键输出的空格,Unicode编码为u0020,空格前后的内容是允许自动换行的。

不换行空格:Unicode编码为u00A0,空格前后的内容是不允许自动换行的。

这里看一下两者的效果,如下图。上面的使用普通空格,而下面的使用不换行空格。

 1 using UnityEngine.UI;
 2 using UnityEngine;
 3 
 4 [RequireComponent(typeof(Text))]
 5 public class NonBreakingSpaceTextComponent : MonoBehaviour {
 6 
 7     public static readonly string no_breaking_space = "u00A0";
 8     protected Text text;
 9 
10     void Awake()
11     {
12         text = this.GetComponent<Text>();
13         text.RegisterDirtyVerticesCallback(OnTextChange);
14     }
15 
16     public void OnTextChange()
17     {
18         if (text.text.Contains(" "))
19         {
20             text.text = text.text.Replace(" ", no_breaking_space);
21         }
22     }
23 }

显然这里选择不换行空格来进行替换。

b.计算图片所占空格数

首先要知道一个空格所占的宽度,图片的宽度,这样才能算出图片占几个空格,对应的,就是将标签替换为几个空格。

2.换行处理

当图片超过文本框边界时,在空格前插入换行符使图片换行。

3.图片位置计算

图片的位置为这些空格所占位置的中间

4.标签格式简化(待优化)

可以使用如{0},{1}这样的方式来简化图片路径标签,然后读取配置替换为真实的路径。

综上,可以得出如下的代码:

  1 using System.Collections.Generic;
  2 using System.Text.RegularExpressions;
  3 using System.Text;
  4 using UnityEngine.EventSystems;
  5 using System;
  6 using UnityEngine;
  7 using UnityEngine.UI;
  8 
  9 //图片<icon name=*** w=1 h=1 n=*** p=***/>
 10 //下划线<material=underline c=#ffffff h=1 n=*** p=***>blablabla...</material>
 11 public class RichText2 : Text {
 12 
 13     private FontData fontData = FontData.defaultFontData;
 14 
 15     //--------------------------------------------------------图片 start
 16     private static readonly string replaceStr = "u00A0";
 17     private static readonly Regex imageTagRegex = new Regex(@"<icon name=([^>s]+)([^>]*)/>");//(名字)(属性)
 18     private static readonly Regex imageParaRegex = new Regex(@"(w+)=([^s]+)");//(key)=(value)
 19     private List<RichTextImageInfo> imageInfoList = new List<RichTextImageInfo>();
 20     private bool isImageDirty = false;
 21     //--------------------------------------------------------图片 end
 22 
 23     protected RichText2()
 24     {
 25         fontData = typeof(Text).GetField("m_FontData", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(this) as FontData;
 26     }
 27 
 28     readonly UIVertex[] m_TempVerts = new UIVertex[4];
 29     protected override void OnPopulateMesh(VertexHelper toFill)
 30     {
 31         if (font == null)
 32             return;
 33 
 34         // We don't care if we the font Texture changes while we are doing our Update.
 35         // The end result of cachedTextGenerator will be valid for this instance.
 36         // Otherwise we can get issues like Case 619238.
 37         m_DisableFontTextureRebuiltCallback = true;
 38 
 39         string richText = text;
 40         IList<UIVertex> verts = null;
 41         richText = CalculateLayoutWithImage(richText, out verts);
 42 
 43         Vector2 extents = rectTransform.rect.size;
 44 
 45         var settings = GetGenerationSettings(extents);
 46         cachedTextGenerator.Populate(text, settings);
 47 
 48         Rect inputRect = rectTransform.rect;
 49 
 50         // get the text alignment anchor point for the text in local space
 51         Vector2 textAnchorPivot = GetTextAnchorPivot(fontData.alignment);
 52         Vector2 refPoint = Vector2.zero;
 53         refPoint.x = Mathf.Lerp(inputRect.xMin, inputRect.xMax, textAnchorPivot.x);
 54         refPoint.y = Mathf.Lerp(inputRect.yMin, inputRect.yMax, textAnchorPivot.y);
 55 
 56         // Determine fraction of pixel to offset text mesh.
 57         Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint;
 58 
 59         // Apply the offset to the vertices
 60         //IList<UIVertex> verts = cachedTextGenerator.verts;
 61         float unitsPerPixel = 1 / pixelsPerUnit;
 62         //Last 4 verts are always a new line...
 63         int vertCount = verts.Count - 4;
 64 
 65         toFill.Clear();
 66         if (roundingOffset != Vector2.zero)
 67         {
 68             for (int i = 0; i < vertCount; ++i)
 69             {
 70                 int tempVertsIndex = i & 3;
 71                 m_TempVerts[tempVertsIndex] = verts[i];
 72                 m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
 73                 m_TempVerts[tempVertsIndex].position.x += roundingOffset.x;
 74                 m_TempVerts[tempVertsIndex].position.y += roundingOffset.y;
 75                 if (tempVertsIndex == 3)
 76                     toFill.AddUIVertexQuad(m_TempVerts);
 77             }
 78         }
 79         else
 80         {
 81             //Debug.Log(unitsPerPixel);
 82             for (int i = 0; i < vertCount; ++i)
 83             {
 84                 int tempVertsIndex = i & 3;
 85                 m_TempVerts[tempVertsIndex] = verts[i];
 86                 m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
 87                 if (tempVertsIndex == 3)
 88                     toFill.AddUIVertexQuad(m_TempVerts);
 89                 //Debug.LogWarning(i + "_" + tempVertsIndex + "_" + m_TempVerts[tempVertsIndex].position);
 90             }
 91         }
 92         m_DisableFontTextureRebuiltCallback = false;
 93     }
 94 
 95     protected string CalculateLayoutWithImage(string richText, out IList<UIVertex> verts)
 96     {
 97         Vector2 extents = rectTransform.rect.size;
 98         var settings = GetGenerationSettings(extents);
 99 
100         float unitsPerPixel = 1 / pixelsPerUnit;
101 
102         float spaceWidth = cachedTextGenerator.GetPreferredWidth(replaceStr, settings) * unitsPerPixel;
103 
104         float fontSize2 = fontSize * 0.5f;
105 
106         //解析图片标签,并将标签替换为空格
107         imageInfoList.Clear();
108         Match match = null;
109         StringBuilder builder = new StringBuilder();
110         while ((match = imageTagRegex.Match(richText)).Success)
111         {
112             RichTextImageInfo imageInfo = new RichTextImageInfo();
113             imageInfo.name = match.Groups[1].Value;
114             string paras = match.Groups[2].Value;
115             if (!string.IsNullOrEmpty(paras))
116             {
117                 var keyValueCollection = imageParaRegex.Matches(paras);
118                 for (int i = 0; i < keyValueCollection.Count; i++)
119                 {
120                     string key = keyValueCollection[i].Groups[1].Value;
121                     string value = keyValueCollection[i].Groups[2].Value;
122                     imageInfo.SetValue(key, value);
123                 }
124             }
125             imageInfo.size = new Vector2(fontSize2 * imageInfo.widthScale, fontSize2 * imageInfo.heightScale);
126             imageInfo.startVertex = match.Index * 4;
127             int num = Mathf.CeilToInt(imageInfo.size.x / spaceWidth);//占据几个空格
128             imageInfo.vertexLength = num * 4;
129             imageInfoList.Add(imageInfo);
130 
131             builder.Length = 0;
132             builder.Append(richText, 0, match.Index);
133             for (int i = 0; i < num; i++)
134             {
135                 builder.Append(replaceStr);
136             }
137             builder.Append(richText, match.Index + match.Length, richText.Length - match.Index - match.Length);
138             richText = builder.ToString();
139         }
140 
141         // Populate charaters
142         cachedTextGenerator.Populate(richText, settings);
143         verts = cachedTextGenerator.verts;
144         // Last 4 verts are always a new line...
145         int vertCount = verts.Count - 4;
146 
147         //换行处理
148         //0 1|4 5|8  9
149         //3 2|7 6|11 10
150         //例如前两个字为图片标签,第三字为普通文字;那么startVertex为0,vertexLength为8
151         for (int i = 0; i < imageInfoList.Count; i++)
152         {
153             RichTextImageInfo imageInfo = imageInfoList[i];
154             int startVertex = imageInfo.startVertex;
155             int vertexLength = imageInfo.vertexLength;
156             int maxVertex = Mathf.Min(startVertex + vertexLength, vertCount);
157             //如果最边缘顶点超过了显示范围,则将图片移到下一行
158             //之后的图片信息中的起始顶点都往后移
159             if (verts[maxVertex - 2].position.x * unitsPerPixel > rectTransform.rect.xMax)
160             {
161                 richText = richText.Insert(startVertex / 2, "
");
162                 for (int j = i; j < imageInfoList.Count; j++)
163                 {
164                     imageInfoList[j].startVertex += 8;
165                 }
166                 cachedTextGenerator.Populate(richText, settings);
167                 verts = cachedTextGenerator.verts;
168                 vertCount = verts.Count - 4;
169             }
170         }
171 
172         //计算位置
173         for (int i = imageInfoList.Count - 1; i >= 0; i--)
174         {
175             RichTextImageInfo imageInfo = imageInfoList[i];
176             int startVertex = imageInfo.startVertex;
177             if (startVertex < vertCount)
178             {
179                 UIVertex uiVertex = verts[startVertex];
180                 Vector2 pos = uiVertex.position;
181                 pos *= unitsPerPixel;
182                 pos += new Vector2(imageInfo.size.x * 0.5f, fontSize2 * 0.5f);
183                 pos += new Vector2(rectTransform.sizeDelta.x * (rectTransform.pivot.x - 0.5f), rectTransform.sizeDelta.y * (rectTransform.pivot.y - 0.5f));
184                 imageInfo.position = pos;
185                 imageInfo.color = Color.white;
186             }
187             else
188             {
189                 imageInfoList.RemoveAt(i);
190             }
191         }
192 
193         isImageDirty = true;
194 
195         return richText;
196     }
197 
198     protected void Update()
199     {
200         if (isImageDirty)
201         {
202             isImageDirty = false;
203 
204             //回收当前的图片
205             Image[] images = GetComponentsInChildren<Image>(true);
206             for (int i = 0; i < images.Length; i++)
207             {
208                 RichTextResourceManager.Instance.SetPoolObject(RichTextResourceType.Image, images[i].gameObject);
209             }
210 
211             //生成图片
212             for (int i = 0; i < imageInfoList.Count; i++)
213             {
214                 RichTextImageInfo imageInfo = imageInfoList[i];
215                 var name = imageInfo.name;
216                 var position = imageInfo.position;
217                 var size = imageInfo.size;
218                 var color = imageInfo.color;
219 
220                 GameObject go = RichTextResourceManager.Instance.GetPoolObject(RichTextResourceType.Image);
221                 Image image = go.GetComponent<Image>();
222                 RichTextResourceManager.Instance.SetSprite(name, image);
223                 go.transform.SetParent(rectTransform);
224                 go.transform.localScale = Vector3.one;
225                 image.rectTransform.anchoredPosition = position;
226                 image.rectTransform.sizeDelta = size;
227                 image.color = color;
228             }
229         }
230     }
231 }

效果如下:

原文地址:https://www.cnblogs.com/lyh916/p/9251911.html