[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,這個方法得到的寬度同樣是像素單位的,因此要做轉換處理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM