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);
}
}
UIRichLabel
最新推荐文章于 2022-09-06 20:17:07 发布