去年五月份的时候,刚加入项目不久,老大交给我一个关于聊天系统任务,期初觉得应该很容易,但是看了文档之后,瞬间头都大了_(:з」∠)_,因为需要支持表情!当时Unity3D版本4.3.x,NGUI版本3.5x,当时版本的NGUI已经支持动态字体,我们的项目也不例外,赶忙就用上了。但是,表情的问题要怎么解决?总不能用颜文字吧(╯‵□′)╯︵┻━┻。如果不用动态字体而使用自己制作的图集字体,倒是可以将表情图片打进字库解决。但是既然我们已经用了动态字体,我就只能另想办法了。
经过两天的研究实践,最终找到一个能够实现的解决办法。主要思路是:
1.定义一个标准行宽度,以此作为基准对文字以及表情进行分行处理;
2.使用特殊符号标记表情(例如:#e001),遍历字符串,凡遇到表情标记则将之与位置记录下来,并使用“ ”(空格,具体数量视表情大小而定)将特殊标记替换。
3.使用Vector3记录以上信息,x为表情的横坐标,y为表情所在行数(即纵坐标),z为表情的ID,即刚才的001,以此确定是哪个表情。使用一个List将所有表情信息存放起来,显示时遍历List即可。
有了以上基本思路,下面只要编码实现,但是在编码过程中还是不可避免的问题——如何得到一段文字的长度?这时,就需要用到一个NGUI封装的一个方法NGUIText.CalculatePrintedSize传入参数为string,返回一个Vector2,表示这段文字的长和宽。下面是核心代码。
protected void CalculateExpressionPos(ref string text) { NGUIText.finalSize = m_chatInput.label.defaultFontSize;//设置当前使用字体大小 lineList.Clear(); int row = 0; int textWidth = 0; int lastStartIndex = 0; string curLine = ""; int length = text.Length; for (int i = 0; i < length; i++) { if (text[i] == '#' && i + 4 < length && text[i + 1] == 'e') { string eName = text.Substring(i + 2, 3); int eIndex = 0; Vector3 ePos = Vector3.zero; if (int.TryParse(eName, out eIndex)) { float fx = 0; text = text.Remove(i, 5); text = text.Insert(i, space);//space = " "; length = text.Length; //这里的CalculatePrintedSize是重载过的, //与原本方法相比多的一个参数自定义行款,替换原方法中的rectWidth即可 textWidth = Mathf.RoundToInt( NGUIText.CalculatePrintedSize( text.Substring(lastStartIndex, i - lastStartIndex), BASELINEWIDTH + 30).x); //BASELINEWIDTH为标准行宽度,30是根据表情大小确定的, //这里的表情大小是30*30 if (textWidth > BASELINEWIDTH - 30) { curLine = text.Substring(lastStartIndex, i - lastStartIndex + 1); lineList.Add(curLine); if (textWidth <= BASELINEWIDTH - 15 || textWidth >= BASELINEWIDTH)//行末尾不够需换行 { fx = 0; row++; lastStartIndex = i; ePos.x = fx - m_offsetX; ePos.y = row; ePos.z = eIndex; } else //行末尾足够不需换行 { fx = textWidth; lastStartIndex = i + space.Length; ePos.x = fx - m_offsetX; ePos.y = row; ePos.z = eIndex; row++; } } else { fx = textWidth; ePos.x = fx - m_offsetX; ePos.y = row; ePos.z = eIndex; } } if (eIndex != 0) { eList.Add(ePos); } if (!expInLine.ContainsKey(row)) //有表情无表情行,以此确定行间距 { expInLine.Add(row, true); } } else //记录换行起始Index { if (i - lastStartIndex < 0) continue; float curWidth = Mathf.RoundToInt( NGUIText.CalculatePrintedSize( text.Substring(lastStartIndex, i - lastStartIndex + 1), BASELINEWIDTH + 30).x); if (curWidth > BASELINEWIDTH) { curLine = text.Substring(lastStartIndex, i - lastStartIndex + 1); lineList.Add(curLine); lastStartIndex = i + 1; row++; } if (i == length - 1) { if (i - lastStartIndex < 0) continue; curLine = text.Substring(lastStartIndex, i - lastStartIndex + 1); lineList.Add(curLine); } } } }
经过以上处理,输出的lineList即为聊天内容,eList为表情信息,expInLine字典存放每行是否存在表情信息。将表情图标打入一个图集,命名为001_1、001_2。。。在显示表情时使用UISpriteAnimation脚本可实现动态表情。最终效果如下:
谢谢观看