zoukankan      html  css  js  c++  java
  • [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 }

    效果如下:

  • 相关阅读:
    用TPLINK 无线网卡设置无线工作环境
    ChartDirector与JFreeChart两款主要web图表工具调研报告
    发现奇怪的问题,TOMCAT居然跟本机网卡的DNS设置有关
    解决Oracle监听器服务不能启动的问题
    JAVA 调用 .NET写的WEBSERVICE
    Windows Forms 实现安全的多线程详解
    异步调用与多线程
    关于.NET异步调用的初步总结
    c#中的多线程同步
    WinForm界面开发
  • 原文地址:https://www.cnblogs.com/lyh916/p/9251911.html
Copyright © 2011-2022 走看看