【Unity3D / UI】UGUI Text 文字調整字間距,並適配對齊方式
阿新 • • 發佈:2018-12-14
問題描述
最近的專案美術提需求要調整遊戲得分顯示的數字間隔,發現UGUI的Text元件只提供了行間距的調整,而無法調整字與字之間的間隔,搜尋之後發現一篇博文 UGUI之修改Text字間距 ,按文中提供的程式碼,可以實現文字字間距調整,但是隻支援左對齊方式,居中對齊和右對齊時,文字依舊是從左向右計算網格位置,佈局都是不對的,因而需要在原文程式碼的基礎上,做出一些調整。
問題分析
UGUI Text 元件中的每個文字,是由兩個網格組成,因而調整字間距,可以通過修改每個字的網格頂點位置來實現。上文提到的博文中,只實現了從左向右以第一個字的座標為起點,依次增加字元寬度和間距,作為偏移量計算出後續每個字的位置。但是右對齊時,文字位置需要從每行最後一個字作為起始位置,依次向左計算偏移量;居中對齊時,需要以第一個字作為起始位置,依次向右計算偏移量,但需要額外減去半行長度,時整行居中。半行長度的計算,需要考慮字元數的奇偶,奇數個字元時,需要額外偏移0.5個字元寬度。 根據以上思路,調整原博文中的程式碼如下:
實現效果
程式碼
using System.Collections.Generic; namespace UnityEngine.UI { [AddComponentMenu("UI/Effects/TextSpacing")] public class TextSpacing : BaseMeshEffect { #region Struct public enum HorizontalAligmentType { Left, Center, Right } public class Line { // 起點索引 public int StartVertexIndex { get { return _startVertexIndex; } } private int _startVertexIndex = 0; // 終點索引 public int EndVertexIndex { get { return _endVertexIndex; } } private int _endVertexIndex = 0; // 該行佔的點數目 public int VertexCount { get { return _vertexCount; } } private int _vertexCount = 0; public Line(int startVertexIndex, int length) { _startVertexIndex = startVertexIndex; _endVertexIndex = length * 6 - 1 + startVertexIndex; _vertexCount = length * 6; } } #endregion public float Spacing = 1f; public override void ModifyMesh(VertexHelper vh) { if (!IsActive() || vh.currentVertCount == 0) { return; } var text = GetComponent<Text>(); if (text == null) { Debug.LogError("Missing Text component"); return; } // 水平對齊方式 HorizontalAligmentType alignment; if (text.alignment == TextAnchor.LowerLeft || text.alignment == TextAnchor.MiddleLeft || text.alignment == TextAnchor.UpperLeft) { alignment = HorizontalAligmentType.Left; } else if(text.alignment == TextAnchor.LowerCenter || text.alignment == TextAnchor.MiddleCenter || text.alignment == TextAnchor.UpperCenter) { alignment = HorizontalAligmentType.Center; } else { alignment = HorizontalAligmentType.Right; } var vertexs = new List<UIVertex>(); vh.GetUIVertexStream(vertexs); // var indexCount = vh.currentIndexCount; var lineTexts = text.text.Split('\n'); var lines = new Line[lineTexts.Length]; // 根據lines陣列中各個元素的長度計算每一行中第一個點的索引,每個字、字母、空母均佔6個點 for (var i = 0; i < lines.Length; i++) { // 除最後一行外,vertexs對於前面幾行都有回車符佔了6個點 if (i == 0) { lines[i] = new Line(0, lineTexts[i].Length + 1); } else if (i > 0 && i < lines.Length - 1) { lines[i] = new Line(lines[i - 1].EndVertexIndex + 1, lineTexts[i].Length + 1); } else { lines[i] = new Line(lines[i - 1].EndVertexIndex + 1, lineTexts[i].Length); } } UIVertex vt; for (var i = 0; i < lines.Length; i++) { for (var j = lines[i].StartVertexIndex; j <= lines[i].EndVertexIndex; j++) { if (j < 0 || j >= vertexs.Count) { continue; } vt = vertexs[j]; var charCount = lines[i].EndVertexIndex - lines[i].StartVertexIndex; if (i == lines.Length - 1) { charCount += 6; } if (alignment == HorizontalAligmentType.Left) { vt.position += new Vector3(Spacing * ((j - lines[i].StartVertexIndex) / 6), 0, 0); } else if (alignment == HorizontalAligmentType.Right) { vt.position += new Vector3(Spacing * (-(charCount - j + lines[i].StartVertexIndex) / 6 + 1), 0, 0); } else if (alignment == HorizontalAligmentType.Center) { var offset = (charCount / 6) % 2 == 0 ? 0.5f : 0f; vt.position += new Vector3(Spacing * ((j - lines[i].StartVertexIndex) / 6 - charCount / 12 + offset), 0, 0); } vertexs[j] = vt; // 以下注意點與索引的對應關係 if (j % 6 <= 2) { vh.SetUIVertex(vt, (j / 6) * 4 + j % 6); } if (j % 6 == 4) { vh.SetUIVertex(vt, (j / 6) * 4 + j % 6 - 1); } } } } } }