Text的文本排版是通过TextGenerator来实现的,它把排版的细节封装在c++层了,我们无法看到,但可以在c#层获取到排版后的详细信息,包括:
每个字形(Glyph)的排版信息,行的排版信息等。
通过把排榜后的信息打印出来,我们就可以大致了解排版的原理
using UnityEngine; using UnityEngine.UI; [RequireComponent(typeof(Text))] public class TestTextGen : MonoBehaviour { void Update() { if (Input.GetKeyDown(KeyCode.Alpha1)) { var text = GetComponent<Text>(); PrintFontInfo(text.font); Debug.Log($"unitPerPixel: {1 / text.pixelsPerUnit}, {text.pixelsPerUnit}"); var textGen = text.cachedTextGenerator; PrintTextGenInfo(text.text, textGen); } } static void PrintFontInfo(Font f) { Debug.Log($"===== font:{f.name}"); Debug.Log($"fontSize:{f.fontSize}, dynamic:{f.dynamic}, ascent:{f.ascent}, lineHeight:{f.lineHeight}"); #if UNITY_EDITOR SerializedObject so = new SerializedObject(f); float fontSize = so.FindProperty("m_FontSize").floatValue; float ascent = so.FindProperty("m_Ascent").floatValue; float lineSpacing = so.FindProperty("m_LineSpacing").floatValue; float descent = 0; SerializedProperty sp_Descent = so.FindProperty("m_Descent"); if (sp_Descent != null) descent = sp_Descent.floatValue; Debug.Log($"fontSize:{fontSize}, ascent:{ascent}, lineSpacing:{lineSpacing}, descent:{descent}"); #endif var fontMat = f.material; if (f.material) { Texture fontTex = fontMat.mainTexture; if (fontTex) Debug.Log($"texture:{fontTex.name}, size:({fontTex.width}, {fontTex.height})"); else Debug.Log($"no font Texture"); } else { Debug.Log($"no font mat"); } Debug.Log($"====="); } static void PrintTextGenInfo(string text, TextGenerator textGen) { Debug.Log($"========== TextGenInfo"); var chs = textGen.characters; Debug.Log($"charCount:{chs.Count}, {textGen.characterCount}, visible:{textGen.characterCountVisible}"); for (int i = 0; i < chs.Count; ++i) { var ch = chs[i]; if (i < text.Length) Debug.Log($"ch_{i}: '{text[i]}', w:{ch.charWidth}, cursoPos:{ch.cursorPos.ToStr()}"); else Debug.Log($"ch_{i}: w:{ch.charWidth}, cursoPos:{ch.cursorPos.ToStr()}"); } //cursorPos和verts_lt的坐标区别是: cursorPos不会超出Text限定框、不会字符重叠, y方向是贴着lineTop, var verts = textGen.verts; Debug.Log($"vertCount:{verts.Count}, {textGen.vertexCount}"); for (var i = 0; i < verts.Count; i += 4) { var lt = verts[i].position; var rt = verts[i + 1].position; var rb = verts[i + 2].position; var rl = verts[i + 3].position; Debug.Log($"quad_{i/4}: lt:{lt.ToStr()}, rt:{rt.ToStr()}, rb:{rb.ToStr()}, rl:{rl.ToStr()}"); } var lines = textGen.lines; Debug.Log($"lineCount:{lines.Count}, {textGen.lineCount}"); float lastLineBottomY = 0; for (int i = 0; i < lines.Count; ++i) { var l = lines[i]; float bottomY = l.topY - l.height; if (i > 0) { float leading = l.topY - lastLineBottomY; Debug.Log($"line_{i}: charIndex:{l.startCharIdx}, lineLeading:{l.leading}_{leading}, lineHeight:{l.height}, line_topY:{l.topY}, line_bottomY:{bottomY}"); } else { Debug.Log($"line_{i}: charIndex:{l.startCharIdx}, lineLeading:{l.leading}, lineHeight:{l.height}, line_topY:{l.topY}, line_bottomY:{bottomY}"); } lastLineBottomY = bottomY; } Debug.Log($"=========="); } }
排版示例1
绿色的线为行top, 蓝色的线为行bottom, 红色的线为基线
1) ascent: 行top位置往下移动ascent的距离就是基线所在位置
2) descent: 基线位置往下移动descent的距离就是行bottom所在的位置
3) line height: 行top和行bottom间的距离就是行高
4) line leading: 下一行top和上一行bottom间的距离就是行间距
排版示例2
标签:Log,textGen,text,var,Debug,ugui,排版,度量 From: https://www.cnblogs.com/sailJs/p/17514700.html