Unity3D NGUI图文混排聊天表情
原創(chuàng)文章如需轉(zhuǎn)載請注明:轉(zhuǎn)載自?脫莫柔Unity3D學(xué)習(xí)之旅?Unity3D引擎技術(shù)交流QQ群:【119706192】本文鏈接地址:?Unity3D NGUI圖文混排的聊天表情
歷時1年開發(fā)的mmorpg游戲終于進(jìn)入收尾階段,最后還差些需要提升表現(xiàn)力的小功能沒做。比如圖文混排聊天表情。網(wǎng)上找了插件對接半天發(fā)現(xiàn)插件各種bug,修復(fù)實(shí)在困難,焦躁之下最終決定自己寫!
最為一個cv戰(zhàn)士,生存的原則就是能ctrl+c ctrl+v 實(shí)現(xiàn)的功能,堅決不自己寫,這么普及的功能,網(wǎng)上肯定有人寫。
然后我就找到了蠻牛的師兄弟寫的這篇文章http://www.manew.com/blog-3649-2595.html
推算不出來他藏起來的NGUIText.CalculatePrintedSize()功能是做了什么實(shí)現(xiàn),我返回的寬度結(jié)果居然是(0,高度),原文展示的代碼部分思路我也看不明白。
沒辦法,還是自己動手吧。于是自己做了一套獲取每個字符累加寬度的方式實(shí)現(xiàn)了一版。核心代碼如下:
void replaceFace(ref string text){eList.Clear();float lineW = 0;float low = 0;float fontSize = mLabel.fontSize;for (int i = 0; i < text.Length; i++){float cWidth = 0;int isface = -1;Debug.Log(text[i]);if (text[i] == '#' && i + 4 < text.Length && text[i + 2] == '_'){cWidth = faceWidth;isface = i;}else{int charW;if (!GetCharWidth(text[i], out charW)){text = text.Remove(isface, faceNamelength);text = text.Insert(isface, spaceChar.ToString());}cWidth += charW;}StringBuilder spaceTemp = new StringBuilder();Debug.Log("預(yù)判" + (lineW + cWidth) + ">" + mLabel.width);if (lineW + cWidth > mLabel.width){lineW = cWidth;low++;Debug.Log("換行");if (isface > 0){spaceTemp.Append("\n") ;Debug.Log("圖片換行補(bǔ)換行符");i += 1;}}else{lineW += cWidth;}if (isface > 0){FacePostion ePos = new FacePostion();ePos.facePackID = text[isface + 1];ePos.faceID = text.Substring(isface + 3, 2);ePos.posX = lineW - faceWidth + m_offsetX;ePos.posY = low * -faceWidth + m_offsetY;eList.Add(ePos);Debug.Log("圖:" + ePos.faceID);for (int j = 0; j < spaceCount; j++)spaceTemp.Append(spaceChar);text = text.Remove(isface, faceNamelength);text = text.Insert(isface, spaceTemp.ToString());i += faceNamelength;}}DrawFace();}此方式,終于實(shí)現(xiàn)了基本的中文字+圖標(biāo)的混合方式。
但是!
連續(xù)的數(shù)字、字母寬度,顯示的寬度居然會縮減(平均沒2個字符減少2像素),經(jīng)細(xì)研究發(fā)現(xiàn),NGUI果然對這些字符做了縮減間距的處理。
不開心!
憑什么UILabel的widget就能獲取正常寬度呢,深入探究NGUI源碼發(fā)現(xiàn),根源就在以上博文中提起的NGUIText.CalculatePrintedSize()方法。寬度獲取失敗的原因居然是我沒對字體賦值。我服你!
回頭又重寫,嗯,秉承大神代碼我看不懂的原則,最終我實(shí)現(xiàn)了完美解決方案。
再次分享在網(wǎng)上以備其它師兄弟備用。看完覺著
public class UILabelTest : MonoBehaviour {UILabel mLabel;UIAtlas faceAtlas;void Awake(){mLabel = GetComponent<UILabel>();// 動態(tài)字體大小賦值(!勿刪!)NGUIText.dynamicFont = mLabel.trueTypeFont;//傻逼要先賦值int charW = (int)(NGUIText.CalculatePrintedSize(spaceChar2.ToString(), true).x);spaceCount = faceWH / charW;if (faceWH % charW != 0)spaceCount += 1;}#region Debugvoid Start (){string str = mLabel.text;replaceFace4(ref str);mLabel.text = str;}#endregion const int faceNamelength = 5;const char spaceChar2 = ',';int faceWH = 22;int spaceCount = 6;/// <summary>/// 表情偏移/// </summary>const float m_offsetX = 1;const float m_offsetY = 8;void replaceFace4(ref string text){if (!string.IsNullOrEmpty(text) && ContainsFace(text)){mLabel.spacingY = faceWH - mLabel.fontSize;NGUIText.dynamicFont = mLabel.trueTypeFont;//傻逼要先賦值eList.Clear();int maxWidth = mLabel.width;float lineW = 0;float lowCount = 0;for (int i = 0; i < text.Length; i++){if (isFaceLabel(text, i)){StringBuilder spaceTemp = new StringBuilder();int isface = i;Vector2 textV = NGUIText.CalculatePrintedSize(text.Substring(0, i),maxWidth, mLabel.fontSize);if (textV.x + faceWH > maxWidth){//直接下一行spaceTemp.Append("\n");i += 1;lineW = 0;lowCount = textV.y + 1;}else{//不換不換就不換lineW = textV.x;lowCount = textV.y;}FacePostion ePos = new FacePostion();ePos.facePackID = text[isface + 1];ePos.faceID = text.Substring(isface + 3, 2);ePos.posX = lineW + m_offsetX;ePos.posY = -lowCount * faceWH + m_offsetY;eList.Add(ePos);spaceTemp.Append("[ffffff00]");for (int j = 0; j < spaceCount; j++){spaceTemp.Append(spaceChar2);}spaceTemp.Append("[-]");text = text.Remove(isface, faceNamelength);text = text.Insert(isface, spaceTemp.ToString());i += faceNamelength;}}DrawFace();}}#region 畫表情List<FacePostion> eList = new List<FacePostion>();List<UISprite> faceSprites = new List<UISprite>();bool ContainsFace(string text){return text.Contains("#0_");}bool isFaceLabel(string text,int index){return (text[index] == '#' && index + 4 < text.Length && text[index + 2] == '_');}void DrawFace(){for (int i = 0; i < eList.Count; i++){UISprite sp = GetSprite(i);sp.gameObject.SetActive(true);sp.spriteName = "#" + eList[i].facePackID + "_" + eList[i].faceID;sp.transform.localPosition = new Vector3(eList[i].posX, eList[i].posY);}for (int i = eList.Count; i < faceSprites.Count; i++){faceSprites[i].gameObject.SetActive(false);}}UISprite GetSprite(int index){if (faceSprites.Count >= index){if (faceAtlas == null)faceAtlas = Resources.Load<UIAtlas>("AtlasImotion/Imotions");UISprite newsp = NGUITools.AddSprite(this.gameObject, faceAtlas, "", mLabel.depth + 100);newsp.MakePixelPerfect();newsp.pivot = UIWidget.Pivot.BottomLeft;faceSprites.Add(newsp);return newsp;}elsereturn faceSprites[index];}class FacePostion{public float posX;public float posY;public char facePackID;public string faceID;}#endregion }然后就是NGUIText.CalculatePrintedSize的核心代碼,加個重載實(shí)現(xiàn)。
public static Vector2 CalculatePrintedSize(string text,int maxW,int fontSize){Vector2 v = new Vector2(0, 1);if (!string.IsNullOrEmpty(text)){if (encoding) text = StripSymbols(text);Prepare(text);float x = 0f, y = 0f, maxX = 0f;int textLength = text.Length, ch = 0, prev = 0;regionWidth = maxW;finalSize = fontSize;for (int i = 0; i < textLength; ++i){ch = text[i];if (ch == '\n'){if (x > maxX) maxX = x;x = 0f;y += 1;continue;}if (ch < ' ') continue;{float w = GetGlyphWidth(ch, prev);if (w != 0f){w += finalSpacingX;if (Mathf.RoundToInt(x + w) > regionWidth){if (x > maxX) maxX = x - finalSpacingX;x = w;y += 1;}else x += w;prev = ch;}}}v.x = x;v.y = y + 1;}return v;}需要注意的地方:
1.uilabel.text必須先賦值,然后再替換才能正確計算字體大小和行大小,所以有表情符號時要賦值2次。
總結(jié)
以上是生活随笔為你收集整理的Unity3D NGUI图文混排聊天表情的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 软件系统分析与设计考试重点、复习指导及复
- 下一篇: 高数:第七章(同济大学第七版)