UGUI實(shí)現(xiàn)隨意調(diào)整Text中的字體間距
UGUI中是沒有可以隨意調(diào)整字體間的距離的方法,仔細(xì)研究一下可以通過控制每個(gè)字體的網(wǎng)格頂點(diǎn)位置進(jìn)行調(diào)整字體之間的距離,分析一下最簡單情況:輸入的文本是單行的,且末尾沒有換行符;
unity在UnityEngine.UI命名空間中定義了一個(gè)BaseMeshEffect抽象類,他提供了一個(gè)抽象方法ModifyMesh(VertexHelper vh),使得可以輕松地獲得text文本中所有字體 的頂點(diǎn)信息,我們的移動(dòng)字體的操作將在這里面進(jìn)行。VertexHelper類主要是用于提供字體網(wǎng)格數(shù)據(jù)的工具類;
上述便是掛載TestSpacingText腳本之后的效果圖。下面貼出代碼
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class TextSpacingTest : BaseMeshEffect { public float spacing = 0; public override void ModifyMesh(VertexHelper vh) { List<UIVertex> vertexs = new List<UIVertex>(); vh.GetUIVertexStream(vertexs); int vertexIndexCount = vertexs.Count; for (int i = 6; i < vertexIndexCount; i++) { UIVertex v = vertexs[i]; v.position += new Vector3(spacing * (i / 6), 0, 0); vertexs[i] = v; if (i % 6 <= 2) { vh.SetUIVertex(v, (i / 6) * 4 + i % 6); } if (i % 6 == 4) { vh.SetUIVertex(v, (i / 6) * 4 + i % 6 - 1); } } } }
分析代碼:
1)首先創(chuàng)建一個(gè)字體間距的變量,然后需要繼承BaseMeshEffect類并且實(shí)現(xiàn)其中的抽象的方法MeshModify()函數(shù)。
2)創(chuàng)建一個(gè)容器從網(wǎng)格信息生成器vh中將字體的頂點(diǎn)信息全部加載保存下來
3)接下來開始遍歷獲取到的頂點(diǎn),我們知道每個(gè)字體是由兩個(gè)三角形的組成的網(wǎng)格,字體是顯示在這樣的網(wǎng)格上的,因此每個(gè)字體也就對(duì)應(yīng)6個(gè)頂點(diǎn)。那么就開始移動(dòng)每個(gè)頂點(diǎn)就可以了。
4)移動(dòng)頂點(diǎn)之后要記得設(shè)置UV頂點(diǎn)與頂點(diǎn)索引的對(duì)應(yīng)關(guān)系,因?yàn)橐粋€(gè)字體網(wǎng)格由兩個(gè)三角形組成,那么就重疊了兩個(gè)頂點(diǎn),故而一個(gè)字體的6個(gè)頂點(diǎn),就只對(duì)應(yīng)4個(gè)UV頂點(diǎn)索引,如上代碼顯示的那樣。
分析如下:
接下來看看比較復(fù)雜的情況:
文本的情況為,可以有多行,或單行,單行、多行時(shí)末尾均可以有換行符。
核心思路:
1)先考慮僅僅是多行且末尾行的末尾沒有換行符的情況,解決了這個(gè)核心問題,再考慮其他的問題。
2)將多行的文本按照換行符進(jìn)行分割,這樣每一行就形成了一個(gè)字符串,此時(shí)對(duì)每一行進(jìn)行上面簡單的操作,就可以實(shí)現(xiàn)移動(dòng)的了。
3)考慮到所有的文本的頂點(diǎn)信息數(shù)據(jù)都存儲(chǔ)在vh中,可以創(chuàng)建一個(gè)行數(shù)據(jù)結(jié)構(gòu)Line以此來存儲(chǔ)每行的基本屬性(比如:本行開始定點(diǎn)的索引位置,結(jié)束頂點(diǎn)的索引位置,所有頂點(diǎn)的數(shù)量)。
4)簡單多行的情況,利用上面的分行的思路就可以解決,接下來分析其他的問題。
5)單行時(shí)末尾有換行符,我們?cè)诜指钭址笠右耘袛嗍欠裼锌沾那闆r ,若有那么就認(rèn)為末尾產(chǎn)生了換行符,此時(shí)空串不再創(chuàng)建LIne對(duì)象,只用創(chuàng)建一個(gè)Line對(duì)象。解法看代碼。
6)多行時(shí)末尾有換行符,同樣用于上面一樣的方法進(jìn)行檢驗(yàn),最后一個(gè)空串不在創(chuàng)建Line對(duì)象,解法看代碼。
7)之后若是想擴(kuò)展修改字體垂直方向的間距也可以在此基礎(chǔ)上修改,非常簡單。
接下來看代碼:
using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Collections.Generic; internal class Line { //每行開始頂點(diǎn)索引 private int startVertexIndex; public int StartVertexIndex { get { return startVertexIndex; } } //每行結(jié)束頂點(diǎn)索引 private int endVertexIndex; public int EndVertexIndex { get { return endVertexIndex; } } //每行頂點(diǎn)總量 private int countVertexIndex; public int CountVertexIndex { get { return countVertexIndex; } } public Line(int startVertexIndex,int countVertexIndex) { this.startVertexIndex = startVertexIndex; this.countVertexIndex = countVertexIndex; this.endVertexIndex = this.startVertexIndex + countVertexIndex - 1; } } /// <summary> /// 這是設(shè)置字體移動(dòng)的核心類 /// 執(zhí)行多重行移動(dòng)的核心算法是:將多重行分開依次進(jìn)行處理,每一行的處理都是前面對(duì)單行處理的子操作 /// 但是由vh是記錄一個(gè)文本中所有的字的頂點(diǎn),所以說需要分清楚每行開始,每行結(jié)束,以及行的字個(gè)數(shù), /// 如此需要?jiǎng)?chuàng)建一個(gè)行的數(shù)據(jù)結(jié)構(gòu),以保存這些信息 /// </summary> public class TextSpacingMulTest : BaseMeshEffect { public float spacing = 0; public override void ModifyMesh(VertexHelper vh) { Text text = GetComponent<Text>(); string[] ls = text.text.Split('\n'); int length = ls.Length; bool isNewLine = false; Line[] line; if (string.IsNullOrEmpty(ls[ls.Length - 1]) == true) { line = new Line[length - 1]; isNewLine = true; } else { line = new Line[length]; } //Debug.Log("ls長度" + ls.Length); for (int i = 0; i < line.Length; i++) { if (i == 0 && line.Length == 1&&isNewLine==false)//解決單行時(shí)沒有換行符的情況 { line[i] = new Line(0, ls[i].Length * 6); break; } if (i == 0&&line.Length>=1)//解決單行時(shí)有換行符的情況,以及多行時(shí)i為0的情況 { line[i] = new Line(0, (ls[i].Length+1) * 6); } else { if (i < line.Length - 1) { line[i] = new Line(line[i - 1].EndVertexIndex + 1, (ls[i].Length + 1) * 6); } else { if (isNewLine == true)//解決多行時(shí),最后一行末尾有換行符的情況 { line[i] = new Line(line[i - 1].EndVertexIndex + 1, (ls[i].Length + 1) * 6); } else { line[i] = new Line(line[i - 1].EndVertexIndex + 1, ls[i].Length * 6); } } } } List<UIVertex> vertexs = new List<UIVertex>(); vh.GetUIVertexStream(vertexs); int countVertexIndex = vertexs.Count; //Debug.Log("頂點(diǎn)總量" + vertexs.Count); for (int i = 0; i < line.Length; i++) { if (line[i].CountVertexIndex == 6) { continue; } for (int k = line[i].StartVertexIndex+6; k <= line[i].EndVertexIndex; k++) { UIVertex vertex = vertexs[k]; vertex.position += new Vector3(spacing * ((k-line[i].StartVertexIndex) / 6), 0, 0); //Debug.Log("執(zhí)行"); vertexs[k] = vertex; if (k % 6 <= 2) { vh.SetUIVertex(vertex, (k / 6) * 4 + k % 6); } if (k % 6 == 4) { vh.SetUIVertex(vertex, (k / 6) * 4 + k % 6 - 1); } } } } }
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
c# 閉包的相關(guān)知識(shí)以及需要注意的地方
這篇文章主要介紹了c# 閉包的相關(guān)知識(shí)以及需要注意的地方,文中講解非常細(xì)致,代碼幫助大家理解和學(xué)習(xí),感興趣的朋友可以參考下2020-06-06C#對(duì)XtraGrid控件實(shí)現(xiàn)主從表關(guān)系綁定
這篇文章介紹了C#對(duì)XtraGrid控件實(shí)現(xiàn)主從表關(guān)系綁定的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06C#中Byte[]和String之間轉(zhuǎn)換的方法
很多朋友不清楚如何在Byte[]和String之間進(jìn)行轉(zhuǎn)換?下面小編給大家?guī)砹薭yte與string轉(zhuǎn)換的方法,感興趣的朋友參考下吧2016-08-08C#調(diào)用AForge實(shí)現(xiàn)攝像頭錄像的示例代碼
這篇文章主要介紹了C#調(diào)用AForge實(shí)現(xiàn)攝像頭錄像的示例代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-09-09詳解C#中的定時(shí)器Timer類及其垃圾回收機(jī)制
這篇文章主要介紹了C#中的定時(shí)器Timer類及其垃圾回收機(jī)制,講解了Timer相關(guān)的單線程異步工作,需要的朋友可以參考下2016-04-04詳解C#批量插入數(shù)據(jù)到Sqlserver中的四種方式
本文主要講解一下在Sqlserver中批量插入數(shù)據(jù)。文中大數(shù)據(jù)批量插入方式一和方式四盡量避免使用,而方式二和方式三都是非常高效的批量插入數(shù)據(jù)方式,需要的朋友可以看下2016-12-12