UIRichLabel

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System;

/*
 * sprite标签格式: <&spritename@height,width&>
 * framesprite标签格式: <%namepre@defautspritename%>
 * button标签格式: <!buttontext@eventid@eventcontent!>
*/
public class UIRichLabel : MonoBehaviour {
	public UILabel _Target;
	// 普通图片的格式
	const string _SpriteRegex = @"<&[\w@\,]{1,}&>";
	const string _Space = @"  ";
	// 帧动画的格式
	const string _FrameSpriteRegex = @"<%[\w@]{1,}%>";
	const string _FrameSpace = @"    ";
	string _Regex;
	// button
	const string _ButtonRegex = @"<![\w@]{1,}!>";
	const string _ButtonSprite = "friend_xiangxi";
	const string _ButtonSpace = @"          ";

	MatchCollection _Sprites;
	MatchCollection _FrameSprites;
	MatchCollection _Buttons;
	// 分割出来的纯文本信息
	List<string> _LableText = new List<string>();
	// 字符位置索引,汉字也算一个字符
	List<int> _IndicesOffset = new List<int>();
	// 所有的富文本信息
	List<RichInfo> _RichInfo = new List<RichInfo>();
	// 缓存的普通图片节点
	List<UISprite> _SpriteNode = new List<UISprite>();
	// 缓存的sprite animation节点
	List<UISpriteAnimation> _FrameNode = new List<UISpriteAnimation>();
	// 缓存的button节点
	List<UIButton> _ButtonNode = new List<UIButton>();

	[SerializeField]
	UIFont _UIFont;
	[SerializeField]
	Font _TTFFont;

	public enum RichType
	{
		Sprite = 1,
		FrameSprite = 2,
		Button = 3,
	}

	class RichInfo : IComparable<RichInfo>
	{
		public Match _Match;
		public RichType _Type;

		public RichInfo(Match match, RichType type)
		{
			_Match = match;
			_Type = type;
		}

		public int CompareTo(RichInfo obj)
		{
			if(this._Match.Index > obj._Match.Index)
			{
				return -1;
			}
			else
			{
				return 1;
			}
		}
	}

	void Awake()
	{
		_Regex = _SpriteRegex;
		_Regex += "|" + _FrameSpriteRegex;
		_Regex += "|" + _ButtonRegex;
		if(_Target == null)
		{
			GameObject go = new GameObject("label");
			go.transform.parent = gameObject.transform;
			go.layer = LayerMask.NameToLayer("UI");
			_Target = go.AddComponent<UILabel>();
		}
		//_Target.spacingY = 5;
	}

	public void SetSpacing(int x, int y)
	{
		if(_Target != null)
		{
			_Target.spacingX = x;
			_Target.spacingY = y;
		}
	}

	public string text
	{
		set
		{
			if (_Regex == null)
			{
				Awake();
			}
			if(_Target == null)
			{
				return;
			}
			// 校准边缘,避免最后的位置放不满半个fontsize,会有换行问题
			_Target.width = (_Target.width/_Target.fontSize)*_Target.fontSize;
			Reset();
			// 把实际的文本内容抽离出来
			_LableText.Clear();
			//_CurOffset.Clear();
			_IndicesOffset.Clear();
			_Target.text = string.Empty;
			_Target.transform.localPosition = Vector3.zero;
			_LableText = new List<string>(Regex.Split(value, _Regex));
			int charCountLine = Mathf.RoundToInt(_Target.width*2/(float)(_Target.fontSize));
			//_LableText.RemoveAll(RemoveEmpty);

			_Sprites = Regex.Matches(value, _SpriteRegex);
			_FrameSprites = Regex.Matches(value, _FrameSpriteRegex);
			_Buttons = Regex.Matches(value, _ButtonRegex);
			BuildRichInfo();

			if(_LableText.Count > 1)
			{
				for (int i = 0; i < _LableText.Count; i++) 
				{
					//Debuger.Log(_Target.CalculateOffsetToFit(_LableText[i]));
					int leftCount = charCountLine - GetStringLen(_Target.text) % charCountLine;
					if(string.IsNullOrEmpty(_LableText[i]))
					{
						if(i == _LableText.Count - 1)
						{
							//_CurOffset.Add(GetStringLen(_Target.text));
							_IndicesOffset.Add(_Target.text.Length);
							continue;
						}
						//_CurOffset.Add(GetStringLen(_Target.text));
						_IndicesOffset.Add(_Target.text.Length);
						if(i < _RichInfo.Count && _RichInfo[i]._Type == RichType.Button)
						{
							if(leftCount >= _ButtonSpace.Length)
							{
								_Target.text += _ButtonSpace;
							}
							else
							{
								for (int ii = 0; ii < leftCount; ii++) 
								{
									_Target.text += " ";
								}
							}
						}
						else if(i < _RichInfo.Count && _RichInfo[i]._Type == RichType.FrameSprite)
						{
							if(leftCount >= _FrameSpace.Length)
							{
								_Target.text += _FrameSpace;
							}
							else
							{
								for (int ii = 0; ii < leftCount; ii++) 
								{
									_Target.text += " ";
								}
							}
						}
						else
						{
							if(leftCount >= 2)
							{
								_Target.text += _Space;
							}
							else
							{
								for (int ii = 0; ii < leftCount; ii++) 
								{
									_Target.text += " ";
								}
							}
						}
						continue;
					}
					_Target.UpdateNGUIText();
					_Target.text += _LableText[i];
					//_CurOffset.Add(GetStringLen(_Target.text));
					_IndicesOffset.Add(_Target.text.Length);
					leftCount = charCountLine - _Target.text.Length % charCountLine;
					if(i < _RichInfo.Count && _RichInfo[i]._Type == RichType.Button)
					{
						if(leftCount >= _ButtonSpace.Length)
						{
							_Target.text += _ButtonSpace;
						}
						else
						{
							for (int ii = 0; ii < leftCount; ii++) 
							{
								_Target.text += " ";
							}
						}
					}
					else if(i < _RichInfo.Count && _RichInfo[i]._Type == RichType.FrameSprite)
					{
						if(leftCount >= _FrameSpace.Length)
						{
							_Target.text += _FrameSpace;
						}
						else
						{
							for (int ii = 0; ii < leftCount; ii++) 
							{
								_Target.text += " ";
							}
						}
					}
					else
					{
						if(i != _LableText.Count - 1)
						{
							if(leftCount >= 2)
							{
								_Target.text += _Space;
							}
							else
							{
								for (int ii = 0; ii < leftCount; ii++) 
								{
									_Target.text += " ";
								}
							}
						}
					}
				}
			}
			else
			{
				_Target.text = value;
			}

			// 根据文本,取出里面的字符索引信息和顶点信息,再根据顶点信息去计算富文本的偏移
			_Target.UpdateNGUIText();
			BetterList<Vector3> verts = new BetterList<Vector3>();
			BetterList<int> indices = new BetterList<int>();
			NGUIText.PrintApproximateCharacterPositions(_Target.text, verts, indices);

			// 处理sprite
			for (int i = 0; i < _Sprites.Count; i++) 
			{
				int index = GetRichInfoListIndex(_Sprites[i]);
				if(index == -1)
				{
					continue;
				}
//				if(index >= _CurOffset.Count)
//				{
//					return;
//				}
				//int startIndex = _CurOffset[index];
				// 计算在第几行
				//int localLine = (int)(startIndex/charCountLine) + 1;
				// 计算在当前的第几个字节
				//int curLinePos = startIndex - charCountLine*(localLine-1);
				// 计算横向偏移
				//int offsetX = Mathf.RoundToInt((curLinePos+1)*_Target.fontSize/2);
				Vector3 pos = verts[_IndicesOffset[index]*2];
				float offsetX = pos.x + _Target.fontSize/2;
				//Debuger.LogError(curLinePos + "==" + verts[_IndicesOffset[index]*2]);
				// 计算纵向偏移
				//int offsetY = _Target.fontSize/2 + Mathf.RoundToInt((localLine-1)*_Target.fontSize);
				float offsetY = pos.y;
				string info = GetSpriteName(_Sprites[i].Value);
				if(info != null)
				{
					string[] splits = info.Split('@');
					string spriteName = splits[0];
					int height = _Target.fontSize;
					int width = _Target.fontSize;
					if(splits.Length > 1)
					{
						string[] spriteInfo = splits[1].Split(',');
						if(spriteInfo.Length > 1)
						{
							int tmpHeight = 0;
							int tmpWidth = 0;
							if(int.TryParse(spriteInfo[0], out tmpHeight))
							{
								height = tmpHeight;
							}
							if(int.TryParse(spriteInfo[1], out tmpWidth))
							{
								width = tmpWidth;
							}
						}
					}

					UISprite node = AddSpriteNode();
					node.depth = _Target.depth + 1;
					node.width = width;
					node.height = height;
					node.transform.localPosition = _Target.transform.localPosition + new Vector3(offsetX, offsetY, 0);
					//Debuger.LogError(_Target.transform.localPosition + "--" + offsetX);
					NGUIAtlasManager.GetInstance().Attach(node, spriteName);
					node.gameObject.SetActive(true);
				}
            }

			for (int i = 0; i < _FrameSprites.Count; i++) 
			{
				int index = GetRichInfoListIndex(_FrameSprites[i]);
				if(index == -1)
				{
					continue;
				}
				Vector3 pos = verts[_IndicesOffset[index]*2];
				float offsetX = pos.x + _Target.fontSize/2;
				float offsetY = pos.y;
				string info = GetFrameSpriteNamePre(_FrameSprites[i].Value);
				if(info != null)
				{
					string[] splits = info.Split('@');
					UISpriteAnimation node = null;
					if(splits.Length >= 2)
					{
						node = AddFrameSprite(splits[0], splits[1]);
					}
					else
					{
						continue;
					}
					node.transform.localPosition = _Target.transform.localPosition + new Vector3(offsetX + 9, offsetY, 0);
					node.gameObject.SetActive(true);
				}
            }

			for (int i = 0; i < _Buttons.Count; i++) 
			{
				int index = GetRichInfoListIndex(_Buttons[i]);
				if(index == -1)
				{
					continue;
				}
				Vector3 pos = verts[_IndicesOffset[index]*2];
				float offsetX = pos.x + _Target.fontSize/2;
				float offsetY = pos.y;
				string info = GetButtonName(_Buttons[i].Value);
				if(info != null)
				{
					string[] splits = info.Split('@');
					UIButton node = null;
					if(splits.Length > 2)
					{
						node = AddButtonNode(splits[0]);
						node.onClick.Clear();
						EventDelegate del = new EventDelegate(this, "OnButtonClick");
						del.parameters[0] = new EventDelegate.Parameter(splits[1]);
						del.parameters[1] = new EventDelegate.Parameter(splits[2]);
						node.onClick.Add(del);
					}
					else
					{
						node = AddButtonNode(info);
					}
					node.transform.localPosition = _Target.transform.localPosition + new Vector3(offsetX + 36, offsetY, 0);
					node.gameObject.SetActive(true);
				}
			}

			//_Target.text = _Target.text.Replace(@"''","[707070]''[-]");
		}
	}

	UISprite AddSpriteNode()
	{
		UISprite cache = GetSpriteNodeFromCache();
		if(cache != null)
		{
			return cache;
		}
		GameObject go = new GameObject("sprite");
		go.layer = LayerMask.NameToLayer("UI");
		go.transform.parent = gameObject.transform;
		go.transform.localScale = Vector3.one;
		UISprite sprite = go.AddComponent<UISprite>();
		_SpriteNode.Add(sprite);
		return sprite;
	}

	UISpriteAnimation AddFrameSprite(string namepre, string defaultname)
	{
		UISpriteAnimation cache = GetFrameSpriteFromCache();
		if(cache != null)
		{
			cache.namePrefix = namepre;
			NGUIAtlasManager.Instance.Attach(cache.Sprite, defaultname);
			return cache;
		}
		GameObject go = new GameObject("framesprite");
		go.layer = LayerMask.NameToLayer("UI");
		go.transform.parent = gameObject.transform;
		go.transform.localScale = Vector3.one;
		UISprite sprite = go.AddComponent<UISprite>();
		NGUIAtlasManager.Instance.Attach(sprite, defaultname);
		sprite.height = _Target.fontSize*2;
		sprite.width = _Target.fontSize*2;
		sprite.depth = _Target.depth + 2;
		cache = go.AddComponent<UISpriteAnimation>();
		cache.namePrefix = namepre;
		cache.Snap = false;
		cache.framesPerSecond = 10;
		_FrameNode.Add(cache);
		return cache;
	}

	UIButton AddButtonNode(string text)
	{
		UIButton cache = GetButtonNodeFromCache();
		if(cache != null)
		{
			UILabel lab = cache.GetComponentInChildren<UILabel>();
			if(lab != null)
			{
				lab.text = text;
			}
			return cache;
		}

		GameObject go = NGUITools.AddChild(gameObject);
		go.name = "Button";
		UISprite bg = NGUITools.AddWidget<UISprite>(go);
		bg.type = UISprite.Type.Sliced;
		bg.name = "Background";
		bg.width = 80;
		bg.height = 35;
		bg.depth = 15;
		NGUIAtlasManager.Instance.Attach(bg, _ButtonSprite);

		UILabel lbl = NGUITools.AddWidget<UILabel>(go);
		if(_UIFont != null)
		{
			lbl.bitmapFont = _UIFont;
			lbl.trueTypeFont = null;
		}
		else
		{
			lbl.bitmapFont = null;
			lbl.trueTypeFont = _TTFFont;
		}
		lbl.text = text;
		lbl.depth = 18;
		lbl.UpdateNGUIText();
		lbl.AssumeNaturalSize();

		// Add a collider
		NGUITools.AddWidgetCollider(go);

		// Add the scripts
		cache = go.AddComponent<UIButton>();
		cache.tweenTarget = bg.gameObject;
		cache.pressed = Color.gray;
		go.AddComponent<UIPlaySound>();
		_ButtonNode.Add(cache);

		return cache;
    }
    
    void Reset()
    {
        for (int i = 0; i < _SpriteNode.Count; i++) {
            if(_SpriteNode[i] != null)
                _SpriteNode[i].gameObject.SetActive(false);
        }
		for (int i = 0; i < _ButtonNode.Count; i++) {
			if(_ButtonNode[i] != null)
				_ButtonNode[i].gameObject.SetActive(false);
		}
    }
    
    UISprite GetSpriteNodeFromCache()
	{
		for (int i = 0; i < _SpriteNode.Count; i++) {
			if(_SpriteNode[i] != null && _SpriteNode[i].gameObject.activeSelf == false)
			{
				return _SpriteNode[i];
			}
		}

		return null;
	}

	UISpriteAnimation GetFrameSpriteFromCache()
	{
		for (int i = 0; i < _FrameNode.Count; i++) {
			if(_FrameNode[i] != null && _FrameNode[i].gameObject.activeSelf == false)
			{
				return _FrameNode[i];
			}
		}
		
		return null;
	}

	UIButton GetButtonNodeFromCache()
	{
		for (int i = 0; i < _ButtonNode.Count; i++) {
			if(_ButtonNode[i] != null && _ButtonNode[i].gameObject.activeSelf == false)
			{
				return _ButtonNode[i];
			}
		}
		
		return null;
	}

	/// <summary>
	/// 根据索引,排序所有富文本信息,要用这个来添加节点
	/// </summary>
	void BuildRichInfo()
	{
		_RichInfo.Clear();
		for (int i = 0; i < _Sprites.Count; i++) {
			_RichInfo.Add(new RichInfo(_Sprites[i], RichType.Sprite));
		}
		for (int i = 0; i < _FrameSprites.Count; i++) {
			_RichInfo.Add(new RichInfo(_FrameSprites[i], RichType.FrameSprite));
		}
		for (int i = 0; i < _Buttons.Count; i++) {
			_RichInfo.Add(new RichInfo(_Buttons[i], RichType.Button));
		}

		_RichInfo.Sort();
		_RichInfo.Reverse();
	}

	/// <summary>
	/// 获取字符长度,一个汉字算2个
	/// </summary>
	/// <returns>The string length.</returns>
	/// <param name="str">String.</param>
	int GetStringLen(string str)
	{
		if(string.IsNullOrEmpty(str))
		{
			return 0;
		}
		return System.Text.Encoding.UTF8.GetBytes(str).Length;
	}

	int GetRichInfoListIndex(Match match)
	{
		for (int i = 0; i < _RichInfo.Count; i++) {
			if(_RichInfo[i]._Match == match)
			{
				return i;
			}
		}
		return -1;
	}

	/// <summary>
	/// 解析图片标签,返回spriteName
	/// </summary>
	/// <returns>The sprite info.</returns>
	/// <param name="expression">Expression.</param>
	string GetSpriteName(string expression)
	{
		if(string.IsNullOrEmpty(expression))
		{
			return null;
		}
		expression = expression.Replace("<&", "");
		expression = expression.Replace("&>", "");

		return expression;
	}

	string GetButtonName(string expression)
	{
		if(string.IsNullOrEmpty(expression))
		{
			return null;
		}
		expression = expression.Replace("<!", "");
		expression = expression.Replace("!>", "");
		
		return expression;
	}

	string GetFrameSpriteNamePre(string expression)
	{
		if(string.IsNullOrEmpty(expression))
		{
			return null;
		}
		expression = expression.Replace("<%", "");
		expression = expression.Replace("%>", "");
		
		return expression;
	}

	public int LineCount
	{
		get
		{
			if(_Target != null)
			{
				return _Target.height / _Target.fontSize;
			}
			
			return -1;
		}
	}

	public int FontSize
	{
		get
		{
			if(_Target != null)
			{
				return _Target.fontSize;
			}
			else
			{
				return 1;
			}
		}
	}

	void OnButtonClick(string eventId, string info)
	{
		int clientEvent = -1;
		if(int.TryParse(eventId, out clientEvent) == false)
		{
			Debug.LogError("eventid is not num!");
			return;
		}
		if(clientEvent >= (int)NTFrame.GameEvent.GameEventID.GECount)
		{
			Debug.LogError("illegal event id!");
			return;
		}
		ClientEvent eve = new ClientEvent();
		eve.AddParameter(info);
		ClientEventManager.Instance.ActiveEvent((NTFrame.GameEvent.GameEventID)clientEvent, eve);
	}
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值