zoukankan      html  css  js  c++  java
  • [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,这个方法得到的宽度同样是像素单位的,因此要做转换处理。

  • 相关阅读:
    098实战 Job的调度
    maven在windows下的安装
    Map的知识点梳理(不包含collections工具类)
    001 LRU-缓存淘汰算法
    Android渲染机制和丢帧分析
    Android性能优化典范
    正确使用Android性能分析工具——TraceView
    android View 绘制完成监听
    那些年我们用过的显示性能指标
    view, surfaceView, invalidate, postInvalidate, 刷新屏幕
  • 原文地址:https://www.cnblogs.com/lyh916/p/9161846.html
Copyright © 2011-2022 走看看