Unity NGUI實現圖文混排

爲什麼要自己寫圖文混排?

 NGUI的UIlabel本身支持圖文混排,只不過只支持位圖字體,侷限性很強,所以在具體項目中很難滿足需求。

自己寫的話,有什麼想法?

圖文混排的基礎功能無非:圖片或紋理和文字的混合排列,點擊行爲、超鏈接、動態支持字號,字色,描邊等功能。

之前倒是接觸過前輩們寫的自定義插件,雖說基本夠用但也存在各種問題,結構複雜,排序算法純屬邏輯堆積,維護複雜。

結構設計?

基本思路:使用stringTag解析數據結構,生成數據隊列。

使用OO:圖文混排中的任何文本,圖像,抽象爲單個Unit對象,定義一個基礎Unit類,包含組件類型,內容記錄等屬性,其他組件繼承基礎組件,並在子類中自定義自己的個性方法,不同子類在構造函數中根據傳入數據,解析自身屬性。並且摒棄邏輯堆疊的排序算法,子類根據傳入數據自己處理組件實現自己的排序算法,除此之外,實現點擊行爲,組件設置等定製行爲。

其他需求:行對其方式(上部對其,中間對其,下部對其),RichUnit工廠,根據外部數據構造源串數據,邊緣裁切算法。

基類及其子類:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum ContentType
{
	none = 0,			//無
	test = 1,			//純文本
	testCanClick = 2,	//純文本可點擊
	icon = 3,			//圖片
	iconCanClick = 4,	//圖片可點擊
	texture = 5,		//紋理
	textureCanClick = 6,//紋理可點擊
	newLine = 7,		//換行
}

public class RichContentUnit {
	//Unit類型
	public ContentType type;

	//傳入的源文本
	public string sourceContent;

	//回傳數據
	public string messageContent;

	public bool init = false;

	//父管理組件
	public NGUIRichContentLabel parent;

	//根據當前行高-調整元素位置
	public void AdjustAllLine(List<UIWidget> currentLine, int maxHeight, float standardY)
	{
		float newPos = 0f;
		for (int i = 0; i < currentLine.Count; i++)
		{
			if (currentLine [i].height < maxHeight)
			{
				Vector3 widgetPos = currentLine [i].transform.localPosition;
				newPos = standardY + currentLine [i].height / 2f - maxHeight / 2f;
				if (Mathf.Abs (newPos - widgetPos.y) > 0.001f)//判定爲位置需要調整
				{
					currentLine [i].transform.localPosition = new Vector3(widgetPos.x,newPos,0);
				}
			}
		}
	}
}

public class RichLabel : RichContentUnit
{
	public int FontSize;
	public string fontColor;
	public string OutLineColor;
	public string content;
	public List<UILabel> labels;

	public RichLabel(ContentType unitType,string content,NGUIRichContentLabel instance)
	{	
		type = unitType;
		content = content.Replace ("\n",string.Empty);

		//文本@字號@字體顏色@描邊顏色@message(點擊時回傳)
		string[] splitStr = content.Split (NGUIRichContentLabel.splitSign);
		if (splitStr != null && splitStr.Length > 1)
		{
			this.content = splitStr [0];
			init = ParseFontSet (splitStr,instance);
			sourceContent = content;
			parent = instance;
			labels = new List<UILabel> ();
		}
		if (init)
			labels.Add(AddComponent (this.content));
	}

	UILabel AddComponent(string contentSingle,int width = 0, int height = 0)
	{
		GameObject o = new GameObject();
		o.name = "Lable";
		o.layer = parent.gameObject.layer;
		o.transform.parent = parent.gameObject.transform;
		o.transform.localScale = Vector3.one;
		o.transform.localPosition = Vector3.zero;

		UILabel label = o.AddComponent<UILabel>() as UILabel;
		label.trueTypeFont = parent.currentFont;
		label.color = NGUIText.ParseColor(fontColor, 0);
		label.fontSize = FontSize;
		label.keepCrispWhenShrunk = UILabel.Crispness.Never;
		label.useFloatSpacing = true;
		label.floatSpacingX = parent.spaceX;
		if (!string.IsNullOrEmpty(OutLineColor))
		{
			label.effectStyle = UILabel.Effect.Outline;
			label.effectColor = NGUITools.ParseColor (OutLineColor,0);
			label.effectDistance = new Vector2 (0,0);
		}
		else
			label.effectStyle = UILabel.Effect.None;

		label.depth = 0;
		label.pivot = UIWidget.Pivot.TopLeft;
		label.alignment = NGUIText.Alignment.Left;
		label.overflowMethod = UILabel.Overflow.ResizeFreely;
		label.text = contentSingle;

		if (type == ContentType.testCanClick)
		{
			BoxCollider colider = o.AddComponent<BoxCollider> ();
			Vector3 colidersize = new Vector3 (label.width,label.fontSize,0);
			colider.size = colidersize;
			colider.center = new Vector3 (label.width / 2, -label.fontSize / 2,0);
			UIEventListener.Get (label.gameObject).onClick = ClickThisLabel;
		}

		return label;
	}

	public void ResetPosition(ref Vector2 pos,ref int maxHeightofthisLine,ref List<UIWidget> currentLine)
	{
		//超越右邊界
		if (pos.x + labels [0].width > parent.Width)
		{
			string allContent = content;

			//需要將當前文本分割成若干段
			int widthNeed = labels [0].width - (parent.Width - (int)pos.x);
			string cutOut = parent.subStringBylength (labels[0],allContent,parent.Width - pos.x);

			//---------------------------------加入殘餘的半行或整行-----------------------------------
			if (!string.IsNullOrEmpty(cutOut))
			{
				labels [0].text = cutOut;
				labels [0].transform.localPosition = new Vector3 (pos.x,pos.y,0);
				//整行對其
				currentLine.Add (labels [0]);
				base.AdjustAllLine (currentLine,maxHeightofthisLine,pos.y);
			}
			else
			{
				labels [0].transform.localPosition = new Vector3 (pos.x,pos.y,0);
				labels [0].text = string.Empty;
			}

			//--------------------------------------截取整行----------------------------------------

			//設置新行起點
			pos.x = 0;
			pos.y -= Mathf.Max(maxHeightofthisLine, labels [0].fontSize);
			pos.y -= parent.spaceY;
			maxHeightofthisLine = 0;				//新增一行需把最大高度置0

			allContent = allContent.Substring (cutOut.Length,allContent.Length - cutOut.Length);

			int wholeRaw = widthNeed / parent.Width;
			UILabel generate = null;

			for (int i = 0; i < wholeRaw; i++)
			{
				cutOut = parent.subStringBylength (labels[0],allContent,parent.Width);

				//加入整行
				if (!cutOut.Equals (string.Empty))
				{
					generate = AddComponent (cutOut,(parent.Width - (int)pos.x),labels [0].height);
					labels.Add (generate);

					//設置位置
					generate.transform.localPosition = new Vector3 (pos.x,pos.y,0f);
					pos.x = 0;
					pos.y -= Mathf.Max(maxHeightofthisLine, generate.fontSize);
					pos.y -= parent.spaceY;
					maxHeightofthisLine = 0;//新增一行需把最大高度置0
					allContent = allContent.Substring (cutOut.Length,allContent.Length - cutOut.Length);
				}
			}

			// 進入下一行之前,清空緩存
			currentLine.Clear ();

			//--------------------------------------截取剩餘行----------------------------------------

			//裁剪整行後,剩餘半行
			if (widthNeed % parent.Width != 0 && !allContent.Equals(string.Empty))
			{
				generate = AddComponent (allContent,widthNeed % parent.Width,labels [0].height);
				labels.Add (generate);

				generate.transform.localPosition = new Vector3 (pos.x,pos.y,0f);
				pos.x += generate.width;
				maxHeightofthisLine = generate.fontSize;
				currentLine.Add (generate);
			}
		}
		else
		{
			labels [0].transform.localPosition = new Vector3 (pos.x,pos.y,0f);
			pos.x += labels [0].width;
			if (labels [0].height > maxHeightofthisLine)
				maxHeightofthisLine = labels [0].height;
			currentLine.Add (labels [0]);
		}

		//根據對其方式,整行對其
		base.AdjustAllLine (currentLine, maxHeightofthisLine,pos.y);
	}

	public void DestorySelf()
	{
		for (int i = 0; i < labels.Count; i++)
		{
			GameObject.DestroyImmediate (labels[i].gameObject);
		}
		labels.Clear ();
	}

	bool ParseFontSet(string[] splitStr, NGUIRichContentLabel instance)
	{
		//文本@字號@字體顏色@描邊顏色@message
		try
		{
			if (splitStr.Length >= 2)
				FontSize = int.Parse (splitStr [1]);
			else
				FontSize = instance.DefaultFontSize;

			if (splitStr.Length >= 3)
				fontColor = splitStr [2];
			else
				fontColor = instance.sDefaultColor;

			if (splitStr.Length >= 4)
				OutLineColor = splitStr [3];
			else
				OutLineColor = string.Empty;

			if(splitStr.Length >=5)
				messageContent = splitStr [4];
			else
				messageContent = string.Empty;
			return true;
		}
		catch
		{
			return false;
		}
	}

	void ClickThisLabel(GameObject obj)
	{
		if (parent.OnClick != null)
			parent.OnClick (messageContent);
	}
}

public class RichIcon: RichContentUnit
{
	public string IconName;
	public string AtlasName;
	public int width;
	public int height;

	public UISprite sprite;

	public RichIcon(ContentType unitType, string content, NGUIRichContentLabel instance)
	{
		type = unitType;

		//圖片名字@圖集名字@寬度@高度@message信息(點擊時回傳)  ----圖集圖片
		string[] splitStr = content.Split (NGUIRichContentLabel.splitSign);
		if (splitStr != null && splitStr.Length >= 4)
		{
			try
			{
				IconName = splitStr [0];
				AtlasName = splitStr [1];
				width = int.Parse (splitStr [2]);
				height = int.Parse (splitStr [3]);

				if (splitStr.Length >= 5)
					messageContent = splitStr [4];
				else
					messageContent = string.Empty;

				parent = instance;
				init = true;
			}
			catch
			{
				init = false;
				Logger.ErrorLog (string.Concat( "RichIcon 構造函數出錯  content :",content));
			}
		}
		if (init)
			SetComponent ();
	 }

	void SetComponent()
	{
		GameObject o = new GameObject();
		o.name = "icon";
		o.layer = parent.gameObject.layer;
		o.transform.parent = parent.gameObject.transform;
		o.transform.localScale = Vector3.one;
		o.transform.localPosition = Vector3.zero;
		sprite = o.AddComponent<UISprite> () as UISprite;
		sprite.atlas = parent.GetAtlas(AtlasName);
		sprite.depth = 0;
		sprite.width = this.width;
		sprite.height = this.height;
		sprite.pivot = UIWidget.Pivot.TopLeft;
		if (type == ContentType.iconCanClick)
		{
			BoxCollider colider = o.AddComponent<BoxCollider> ();
			colider.size = new Vector3 (this.width,this.height,0);
			colider.center = new Vector3 (this.width / 2, -this.height / 2);
			//回調處理
			UIEventListener.Get(sprite.gameObject).onClick = ClickThisIcon;
		}
		if (!string.IsNullOrEmpty (AtlasName) && sprite.atlas != null)  		//圖集圖片
		{
			sprite.spriteName = IconName;
		}
	}

	public void ResetPosition(ref Vector2 pos,ref int maxHeightofthisLine,ref List<UIWidget> currentLine)
	{
		//超越右邊界
		if (pos.x + sprite.width > parent.Width)
		{
			//重置基準點至下一行
			pos.x = 0;
			pos.y -= maxHeightofthisLine;
			pos.y -= parent.spaceY;
			maxHeightofthisLine = 0;
			currentLine.Clear ();
		}

		sprite.transform.localPosition = new Vector3 (pos.x,pos.y,0f);
		pos.x += sprite.width;
		if (sprite.height > maxHeightofthisLine)
			maxHeightofthisLine = sprite.height;

		currentLine.Add (sprite);
		//根據對其方式,整行對其
		base.AdjustAllLine (currentLine, maxHeightofthisLine,pos.y);
	}

	public void DestorySelf()
	{
		if (sprite != null)
			GameObject.DestroyImmediate (sprite.gameObject);
		sprite = null;
	}

	void ClickThisIcon(GameObject obj)
	{
		if (parent.OnClick != null)
			parent.OnClick (messageContent);
	}
}

public class RichTexture: RichContentUnit
{
	public string IconName;
	public int width;
	public int height;

	public UITexture texture;

	public RichTexture(ContentType unitType,string content, NGUIRichContentLabel instance)
	{
		type = unitType;

		//圖片名字@寬度@高度@message(點擊時回傳)  ----紋理圖片
		string[] splitStr = content.Split (NGUIRichContentLabel.splitSign);
		if (splitStr != null && splitStr.Length >= 3)
		{
			IconName = splitStr [0];
			width = int.Parse (splitStr [1]);
			height = int.Parse (splitStr [2]);
			if (splitStr.Length >= 4)
				messageContent = splitStr [3];
			else
				messageContent = string.Empty;
			parent = instance;
			init = true;
		}

		if (init)
			SetComponent ();
	}

	void SetComponent()
	{
		GameObject o = new GameObject();
		o.name = "texture";
		o.layer = parent.gameObject.layer;
		o.transform.parent = parent.gameObject.transform;
		o.transform.localScale = Vector3.one;
		o.transform.localPosition = Vector3.zero;
		texture = o.AddComponent<UITexture> () as UITexture;
		texture.depth = 0;
		texture.width = this.width;
		texture.height = this.height;
		texture.pivot = UIWidget.Pivot.TopLeft;
		if (type == ContentType.textureCanClick)
		{
			BoxCollider colider = o.AddComponent<BoxCollider> ();
			colider.size = new Vector3 (this.width,this.height,0);
			colider.center = new Vector3 (this.width / 2, -this.height / 2);
			//回調處理
			UIEventListener.Get(texture.gameObject).onClick = ClickThisTexture;
		}
		if (!string.IsNullOrEmpty (IconName))  		//圖集圖片
		{
			//CommonUtils.SetTextureAsync (texture,IconName);
		}
	}

	public void ResetPosition(ref Vector2 pos,ref int maxHeightofthisLine,ref List<UIWidget> currentLine)
	{
		//超越右邊界
		if (pos.x + texture.width > parent.Width)
		{
			//重置基準點至下一行
			pos.x = 0;
			pos.y -= maxHeightofthisLine;
			pos.y -= parent.spaceY;
			maxHeightofthisLine = 0;
			currentLine.Clear ();
		}

		texture.transform.localPosition = new Vector3 (pos.x,pos.y,0f);
		pos.x += texture.width;
		if (texture.height > maxHeightofthisLine)
			maxHeightofthisLine = texture.height;

		currentLine.Add (texture);
		//根據對其方式,整行對其
		base.AdjustAllLine (currentLine, maxHeightofthisLine,pos.y);
	}

	public void DestorySelf()
	{
		if (texture != null)
			GameObject.DestroyImmediate (texture.gameObject);
		texture = null;
	}

	void ClickThisTexture(GameObject obj)
	{
		if (parent.OnClick != null)
			parent.OnClick (messageContent);
	}
}

public class RichNewLine : RichContentUnit
{
	public RichNewLine (string content, NGUIRichContentLabel instance)
	{
		this.type = ContentType.newLine;
		this.init = true;
		this.parent = instance;
	}

	public void ResetPosition(ref Vector2 pos,ref int maxHeightofthisLine,ref List<UIWidget> currentLine)
	{
		pos.y -= (maxHeightofthisLine + parent.DefaultFontSize);
		pos.y -= parent.spaceY;
		pos.x = 0;
		maxHeightofthisLine = 0;
		currentLine.Clear ();
	}
}
組件類:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;

public class NGUIRichContentLabel : MonoBehaviour {

	public string Content = string.Empty;

	public int Width = 500;

	public int Height = 500;

	public List<Font> unityFont = null;

	public int fontIndex = 0;

	public int DefaultFontSize = 20;

	public List<UIAtlas> Atlases = null;

	public string sDefaultColor = "[ffffffff]";

	public Color DefaultColor = Color.white;

	public float spaceX = 0;

	public float spaceY = 0;

	#region 屬性接口

	public string SetContent
	{
		get
		{
			return Content;
		}
		set
		{
			this.Content = value;
			FillAll ();
		}
	}

	public int SetWdith
	{
		get
		{
			return this.Width;
		}
		set
		{
			this.Width = value;
			FillAll ();
		}
	}

	public int SetHeight
	{
		get
		{
			return this.Height;
		}
		set
		{
			this.Height = value;
			FillAll ();
		}
	}

	public int SetFontIndex
	{
		get
		{
			return fontIndex;
		}
		set
		{
			this.fontIndex = value;
			FillAll ();
		}
	}

	public int SetDefaultFontSize
	{
		get
		{
			return DefaultFontSize;
		}
		set
		{
			this.DefaultFontSize = value;
			FillAll ();
		}
	}

	public string SetDefaultColor
	{
		get
		{
			return sDefaultColor;
		}
		set
		{
			this.sDefaultColor = value; 
			this.DefaultColor = NGUIText.ParseColor(this.sDefaultColor, 0);
			FillAll ();
		}
	}

	public Font currentFont
	{
		get
		{
			if (unityFont != null && fontIndex < unityFont.Count)
				return unityFont [fontIndex];
			return null;
		}
	}

	//獲取目標圖集
	public UIAtlas GetAtlas(string atlasName)
	{
		foreach (UIAtlas atlas in Atlases)
		{
			if (atlas.name.Equals (atlasName))
			{
				return atlas;
				break;
			}
		}
		return null;
	}

	#endregion

	//字符串轉義常量

	public static char splitSign= '@';							//數據解析分隔符

	public static string fontStart = "<font>";					//文本開始

	public static string fontEnd = "</font>";					//文本結束

	public static string linkStart = "<link>";					//鏈接開始

	public static string linkEnd = "</link>";					//鏈接結束

	public static string iconStart = "<icon>";					//圖標開始

	public static string iconEnd = "</icon>";					//圖標結束

	public static string iconClick = "<iconClick>";				//可點擊圖標開始

	public static string iconClickEnd = "</iconClick>";			//可點擊圖標結束

	public static string textureStart = "<texture>";			//紋理開始

	public static string textureEnd = "</texture>";				//紋理結束

	public static string textureClick = "<textureClick>";		//可點擊紋理開始

	public static string textureClickEnd = "</textureClick>";	//可點擊紋理結束

	public static string newLineStart = "<n>";		//換行轉義字符

	//所有的富文本單元
	List<RichContentUnit> units = new List<RichContentUnit> ();

	//分段解析字符
	private string[] splitForStart = new string[] { fontStart,iconStart,textureStart};

	//UI根節點
	private UIRoot _root;

	public delegate void ClickRichUnit(string data);
	//點擊行爲的回調
	public ClickRichUnit OnClick = null;

	void Start()
	{
		GameObject o = NGUITools.GetRoot(gameObject);
		if (o != null)
			_root = o.GetComponent<UIRoot>() as UIRoot;
	}

	void Update () {
		if (Input.GetKeyUp (KeyCode.F1))
		{
			//枚舉類型@文本@字號@字體顏色@描邊顏色

			Content = "<font>a11111111111111111111111111今天是個好日子,你們覺得呢/反正我覺得挺好,啦啦啦啦啦啦啦啦啦啦啦,話說回來可以啊,alliswell@20@ffffffff@00ff00ff</font>"
				+ "<icon>pic_tongyong_faqiu_zhanshi@CommonAtlas@50@50</icon>"
				+ "<font>善惡到頭終有報,人間正道是滄桑!@25@07F4E0FF</font>"
				+ "<texture>pic_zhujiemian_xiaoditu_yingdi@100@100</texture>"
				//+ newLineStart
				+ "<font>奧特曼打\n小怪獸@20@ffffffff@ff0000ff</font>";
			
			FillAll ();
		}
		if (Input.GetKeyUp (KeyCode.F2))
		{
			FillAll ();
		}
	}

	/// <summary>
	/// 重刷富文本
	/// </summary>
	void FillAll()
	{
		ClearOld ();
		units = TransformToUnit (Content);
		UpdateWidget ();
	}

	/// <summary>
	/// 刷新排布
	/// </summary>
	void UpdateWidget()
	{
		//當前可排布位置
		Vector2 pos = Vector2.zero;

		//當前行最大高度
		int maxHeightPerLine = 0;

		//當前行組件緩存
		List<UIWidget> currentLine = new List<UIWidget> ();

		for (int i = 0; i < units.Count; i++)
		{
			if (units [i].type == ContentType.test || units [i].type == ContentType.testCanClick)
				((RichLabel)units [i]).ResetPosition (ref pos,ref maxHeightPerLine,ref currentLine);
			else if (units [i].type == ContentType.icon|| units [i].type == ContentType.iconCanClick)
				((RichIcon)units [i]).ResetPosition (ref pos,ref maxHeightPerLine,ref currentLine);
			else if (units [i].type == ContentType.texture || units [i].type == ContentType.textureCanClick )
				((RichTexture)units [i]).ResetPosition (ref pos,ref maxHeightPerLine,ref currentLine);
			else if (units [i].type == ContentType.newLine)
				((RichNewLine)units [i]).ResetPosition (ref pos,ref maxHeightPerLine,ref currentLine);
		}
	}

	/// <summary>
	/// 清除組件
	/// </summary>
	void ClearOld()
	{
		for (int i = 0; i < units.Count; i++)
		{
			if (units [i].type == ContentType.test || units [i].type == ContentType.testCanClick)
				((RichLabel)units [i]).DestorySelf ();
			else if (units [i].type == ContentType.icon|| units [i].type == ContentType.iconCanClick)
				((RichIcon)units [i]).DestorySelf ();
			else if (units [i].type == ContentType.texture|| units [i].type == ContentType.textureCanClick)
				((RichTexture)units [i]).DestorySelf ();
		}
		units.Clear ();
	}

	/// <summary>
	/// 源字符串解析
	/// </summary>
	/// <returns>The to unit.</returns>
	/// <param name="content">Content.</param>
	List<RichContentUnit> TransformToUnit(string content)
	{
		List<RichContentUnit> returnValue = new List<RichContentUnit> ();

		string[] newLineParse = content.Split (new string[] { newLineStart},System.StringSplitOptions.RemoveEmptyEntries);

		for (int index = 0; index < newLineParse.Length; index++)
		{
			string[] res = newLineParse[index].Split (splitForStart,System.StringSplitOptions.RemoveEmptyEntries);
			for(int i = 0; i < res.Length;i++)
			{
				switch (GenerateType (ref res [i]))
				{
					case ContentType.icon:
						returnValue.Add (new RichIcon(ContentType.icon,res [i],this));
						break;
					case ContentType.iconCanClick:
						returnValue.Add (new RichIcon(ContentType.iconCanClick,res [i],this));
						break;
					case ContentType.test:
						returnValue.Add (new RichLabel(ContentType.test,res [i],this));
						break;
					case ContentType.testCanClick:
						returnValue.Add (new RichLabel(ContentType.testCanClick,res [i],this));
						break;
					case ContentType.texture:
						returnValue.Add (new RichTexture(ContentType.texture,res [i],this));
						break;
					case ContentType.textureCanClick:
						returnValue.Add (new RichTexture(ContentType.textureCanClick,res [i],this));
						break;
					case ContentType.none:
						continue;
				}
			}

			//換行
			if(index < newLineParse.Length - 1)
				returnValue.Add (new RichNewLine(newLineStart,this));
		}


		return returnValue;
	}

	/// <summary>
	/// 解析Unit類型
	/// </summary>
	/// <returns>The type.</returns>
	/// <param name="content">Content.</param>
	ContentType GenerateType(ref string content)
	{
		if (content.Contains (fontEnd))
		{
			content = content.Replace (fontEnd,string.Empty);
			return ContentType.test;
		}
		else if (content.Contains (linkEnd))
		{
			content = content.Replace (fontEnd,string.Empty);
			return ContentType.testCanClick;
		}
		else if (content.Contains (iconEnd))
		{
			content = content.Replace (iconEnd,string.Empty);
			return ContentType.icon;
		}
		else if ( content.Contains (iconClickEnd))
		{
			content = content.Replace (iconEnd,string.Empty);
			return ContentType.iconCanClick;
		}
		else if (content.Contains (textureEnd))
		{
			content = content.Replace (textureEnd,string.Empty);
			return ContentType.texture;
		}
		else if (content.Contains (textureClickEnd))
		{
			content = content.Replace (textureEnd,string.Empty);
			return ContentType.textureCanClick;
		}

		return ContentType.none;
	}

	/// <summary>
	/// 字符串按寬度截取
	/// </summary>
	/// <returns>The string bylength.</returns>
	/// <param name="label">Label.</param>
	/// <param name="content">Content.</param>
	/// <param name="length">Length.</param>
	public string subStringBylength(UILabel label, string content, float length)
	{
		//需取出更準確的字體大小
		float realWidth = 0;
		for (int i = 0; i < content.Length; i++)
		{
			realWidth += GetGlyphWidth (label,content[i],0);

			if (realWidth > length)
			{
				return content.Substring (0,i);
			}

			realWidth += spaceX;
		}

		return content;
	}

	//// <summary>
	/// 獲得文字的寬
	/// 使用字號,快速但不準確
	/// </summary>
	float GetFontSizeWidth(UILabel label)
	{
		if (label == null) return 0f;
		return label.fontSize;
	}

	//// <summary>
	/// 獲得文字的寬
	/// 使用NGUIText函數
	/// </summary>
	float GetNGUITextGlyphWidth(UILabel label, int ch, int prev)
	{
		if (label == null) return 0f;
		//準備數據
		bool keepCrisp;
		float pixelDensity;
		int finalSize;
		float fontScale;
		if (label.trueTypeFont != null)
		{
			NGUIText.dynamicFont = label.trueTypeFont;
			NGUIText.bitmapFont = null;
		}
		else
		{
			NGUIText.bitmapFont = label.font;
			NGUIText.dynamicFont = null;
		}
		if (label.trueTypeFont != null && label.keepCrispWhenShrunk != UILabel.Crispness.Never)
		{
			#if UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_WP_8_1 || UNITY_BLACKBERRY
			keepCrisp = (label.keepCrispWhenShrunk == UILabel.Crispness.Always);
			#else
			keepCrisp = true;
			#endif
		}
		else
			keepCrisp = false;

		pixelDensity = 1.0f;
		if (label.trueTypeFont != null && keepCrisp)
			pixelDensity = (_root != null) ? _root.pixelSizeAdjustment : 1f;
		else
			pixelDensity = 1f;
		finalSize = Mathf.RoundToInt(label.fontSize / pixelDensity);
		fontScale = 1.0f;
		//
		NGUIText.fontStyle = label.fontStyle;
		NGUIText.finalSize = finalSize;
		NGUIText.pixelDensity = pixelDensity;
		NGUIText.fontScale = fontScale;
		NGUIText.Update(true);
		return NGUIText.GetGlyphWidth(ch, prev,fontScale); //2018/1/22
	}

	//// <summary>
	/// 獲得文字的寬
	/// 使用unity內部函數
	/// </summary>
	float GetGlyphWidth(UILabel label,int ch, int prev)
	{
		if (label == null) return 0f;
		//準備數據
		bool keepCrisp;
		float pixelDensity;
		int finalSize;
		float fontScale;
		if (label.trueTypeFont != null && label.keepCrispWhenShrunk != UILabel.Crispness.Never)
		{
			#if UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_WP_8_1 || UNITY_BLACKBERRY
			keepCrisp = (label.keepCrispWhenShrunk == UILabel.Crispness.Always);
			#else
			keepCrisp = true;
			#endif
		}
		else
			keepCrisp = false;
		pixelDensity = 1.0f;
		if (label.trueTypeFont != null && keepCrisp)
			pixelDensity = (_root != null) ? _root.pixelSizeAdjustment : 1f;
		else
			pixelDensity = 1f;
		finalSize = Mathf.RoundToInt(label.fontSize / pixelDensity);
		fontScale = 1.0f;
		//
		label.trueTypeFont.RequestCharactersInTexture(label.text, finalSize, label.fontStyle);
		if (label.trueTypeFont != null)
		{
			CharacterInfo mTempChar;
			if (label.trueTypeFont.GetCharacterInfo((char)ch, out mTempChar, finalSize, label.fontStyle))
				#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6
				return mTempChar.width * fontScale * pixelDensity;
				#else
				return mTempChar.advance * fontScale * pixelDensity;
				#endif
		}

		return 0f;
	}


}







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章