• [UGUI]图文混排(二):Text源码分析


    UGUI源码:

    https://bitbucket.org/Unity-Technologies/ui/downloads/?tab=tags

    首先下载一份UGUI源码,这里我下载的版本是5.3.2f1。然后找到Text.cs,里面有方法OnPopulateMesh,这个方法会修改文字的顶点。而图文混排,涉及到顶点数据的修改。因此,我们的重点就是对这个方法进行修改,这里给出一个最简单的重写版本,它和普通的text是一样的。Text的渲染过程是由TextGenerator产生顶点数据,配合字体产生的贴图最终显示在屏幕上。

     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 //下划线<material=underline c=#ffffff h=1 n=*** p=***>blablabla...</material>
    10 public class RichTextTest : Text {
    11 
    12     private FontData fontData = FontData.defaultFontData;
    13 
    14     protected RichTextTest()
    15     {
    16         fontData = typeof(Text).GetField("m_FontData", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(this) as FontData;
    17     }
    18 
    19     readonly UIVertex[] m_TempVerts = new UIVertex[4];
    20     protected override void OnPopulateMesh(VertexHelper toFill)
    21     {
    22         if (font == null)
    23             return;
    24 
    25         // We don't care if we the font Texture changes while we are doing our Update.
    26         // The end result of cachedTextGenerator will be valid for this instance.
    27         // Otherwise we can get issues like Case 619238.
    28         m_DisableFontTextureRebuiltCallback = true;
    29 
    30         Vector2 extents = rectTransform.rect.size;
    31 
    32         var settings = GetGenerationSettings(extents);
    33         cachedTextGenerator.Populate(text, settings);
    34 
    35         Rect inputRect = rectTransform.rect;
    36 
    37         // get the text alignment anchor point for the text in local space
    38         Vector2 textAnchorPivot = GetTextAnchorPivot(fontData.alignment);
    39         Vector2 refPoint = Vector2.zero;
    40         refPoint.x = Mathf.Lerp(inputRect.xMin, inputRect.xMax, textAnchorPivot.x);
    41         refPoint.y = Mathf.Lerp(inputRect.yMin, inputRect.yMax, textAnchorPivot.y);
    42 
    43         // Determine fraction of pixel to offset text mesh.
    44         Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint;
    45 
    46         // Apply the offset to the vertices
    47         IList<UIVertex> verts = cachedTextGenerator.verts;
    48         float unitsPerPixel = 1 / pixelsPerUnit;
    49         //Last 4 verts are always a new line...
    50         int vertCount = verts.Count - 4;
    51 
    52         toFill.Clear();
    53         if (roundingOffset != Vector2.zero)
    54         {
    55             for (int i = 0; i < vertCount; ++i)
    56             {
    57                 int tempVertsIndex = i & 3;
    58                 m_TempVerts[tempVertsIndex] = verts[i];
    59                 m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
    60                 m_TempVerts[tempVertsIndex].position.x += roundingOffset.x;
    61                 m_TempVerts[tempVertsIndex].position.y += roundingOffset.y;
    62                 if (tempVertsIndex == 3)
    63                     toFill.AddUIVertexQuad(m_TempVerts);
    64             }
    65         }
    66         else
    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                 if (tempVertsIndex == 3)
    74                     toFill.AddUIVertexQuad(m_TempVerts);
    75             }
    76         }
    77         m_DisableFontTextureRebuiltCallback = false;
    78     }
    79 }

    分析一下上面的代码是怎么实现的:

    首先,复制OnPopulateMesh这个方法,发现需要m_TempVerts这个变量,这个变量其实充当临时变量的作用,因此直接复制过来即可。然后提示需要m_FontData这个变量,这个变量是FontData类型的,因此跳到FontData.cs,发现FontData这个东西几乎就是Text在Inspector面板上的东西,但是m_FontData是私有的,这里可以通过反射去获取这个私有变量,又因为序列化的原因,不能同名,所以这里使用变量名fontData。

    内部源码分析:

    1.unitsPerPixel

    意思为每像素单位,即一个像素占几个unity单位。因此可以推出这个cachedTextGenerator.verts是像素单位(cachedTextGenerator.verts赋值给m_TempVerts,然后再做乘法)。那么这个变量的作用是什么呢?可以通过改变Game视图的分辨率,然后打印下,发现随分辨率变化,这个值也在变化,不过文字在矩形框的位置还是不变的,因此可以推测这个是用于自适应的。

    2.m_TempVerts

    在Text控件中赋值2个字,然后在循环中添加代码:Debug.LogWarning(i + "_" + tempVertsIndex + "_" + m_TempVerts[tempVertsIndex].position);,结果如下图。

    可以看到,1个字符有4个顶点,而顶点的排列如下:

    3.顶点的生成

    通过OnPopulateMesh这个方法可以看到,生成顶点的方法如下。不过生成的顶点要去掉最后四个点,可以打印一下看看最后四个点的位置。至于为什么要这样处理呢,因为TextGenerator这个类是在UnityEngine命名空间下的,所以我们就不得而知了...

    Vector2 extents = rectTransform.rect.size;
    var settings = GetGenerationSettings(extents);
    cachedTextGenerator.Populate(text, settings);
    IList<UIVertex> verts = cachedTextGenerator.verts;
    //Last 4 verts are always a new line...
    int vertCount = verts.Count - 4;

    4.获取字符串的长度

    TextGenerator类中的GetPreferredWidth方法可以获取字符串的长度。具体使用方式可以看Text类中的preferredWidth,这个方法得到的宽度同样是像素单位的,因此要做转换处理。

  • 相关阅读:
    OSPF
    【今日CS 视觉论文速览】 24 Jan 2019
    【今日CS 视觉论文速览】Wed, 23 Jan 2019
    【今日CS 视觉论文速览】 21 Jan 2019
    【Processing学习笔记】安装与入门
    【今日CS 视觉论文速览】Part2, 18 Jan 2019
    【今日CS 视觉论文速览】Fri, 18 Jan 2019
    【今日CS 视觉论文速览】Thu, 17 Jan 2019
    【今日CS 视觉论文速览】Part2, 16 Jan 2019
    【今日CS 视觉论文速览】Wed, 16 Jan 2019
  • 原文地址:https://www.cnblogs.com/lyh916/p/9161846.html
Copyright © 2020-2023  润新知