为什么要自己写图文混排?
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].transfo