网上找了插件对接半天发现插件各种bug,修复实在困难,焦躁之下最终决定自己写!
最为一个cv战士,生存的原则就是能ctrl+c ctrl+v 实现的功能,坚决不自己写,这么普及的功能,网上肯定有人写。
然后我就找到了蛮牛的师兄弟写的这篇文章http://www.manew.com/blog-3649-2595.html
推算不出来他藏起来的NGUIText.CalculatePrintedSize()功能是做了什么实现,我返回的宽度结果居然是(0,高度),原文展示的代码部分思路我也看不明白。
没办法,还是自己动手吧。于是自己做了一套获取每个字符累加宽度的方式实现了一版。核心代码如下:
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("预判" + (lineW + cWidth) + ">" + mLabel.width);
if (lineW + cWidth > mLabel.width)
{
lineW = cWidth;
low++;
Debug.Log("换行");
if (isface > 0)
{
spaceTemp.Append("\n") ;
Debug.Log("图片换行补换行符");
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();
}
但是!
连续的数字、字母宽度,显示的宽度居然会缩减(平均没2个字符减少2像素),经细研究发现,NGUI果然对这些字符做了缩减间距的处理。
不开心!
凭什么UILabel的widget就能获取正常宽度呢,深入探究NGUI源码发现,根源就在以上博文中提起的NGUIText.CalculatePrintedSize()方法。宽度获取失败的原因居然是我没对字体赋值。我服你!
回头又重写,嗯,秉承大神代码我看不懂的原则,最终我实现了完美解决方案。
再次分享在网上以备其它师兄弟备用。看完觉着
public class UILabelTest : MonoBehaviour
{
UILabel mLabel;
UIAtlas faceAtlas;
void Awake()
{
mLabel = GetComponent();
// 动态字体大小赋值(!勿删!)
NGUIText.dynamicFont = mLabel.trueTypeFont;//傻逼要先赋值
int charW = (int)(NGUIText.CalculatePrintedSize(spaceChar2.ToString(), true).x);
spaceCount = faceWH / charW;
if (faceWH % charW != 0)
spaceCount += 1;
}
#region Debug
void 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;
///
/// 表情偏移
///
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 eList = new List();
List faceSprites = new List();
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("AtlasImotion/Imotions");
UISprite newsp = NGUITools.AddSprite(this.gameObject, faceAtlas, "", mLabel.depth + 100);
newsp.MakePixelPerfect();
newsp.pivot = UIWidget.Pivot.BottomLeft;
faceSprites.Add(newsp);
return newsp;
}
else
return faceSprites[index];
}
class FacePostion
{
public float posX;
public float posY;
public char facePackID;
public string faceID;
}
#endregion
}
然后就是NGUIText.CalculatePrintedSize的核心代码,加个重载实现。
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次。