参考链接:

http://www.cnblogs.com/leoin2012/p/7162099.html

0.图片标签和图片类

标签格式:<icon name=*** w=1 h=1 n=*** p=***/>

RichTextImageInfo.cs

 using UnityEngine;

 public class RichTextImageInfo
{
public string name; //名字(路径)
public Vector2 size; //宽高
public Vector2 position; //位置
public int startVertex; //起始顶点
public int vertexLength; //占据顶点数
public Color color; //颜色 //标签属性
public float widthScale = 1f;//宽度缩放
public float heightScale = 1f;//高度缩放
public string eventName;//事件名
public string eventParameter;//事件参数 public void SetValue(string key, string value)
{
switch (key)
{
case "w":
{
float.TryParse(value, out widthScale);
break;
}
case "h":
{
float.TryParse(value, out heightScale);
break;
}
case "n":
{
eventName = value;
break;
}
case "p":
{
eventParameter = value;
break;
}
default:
break;
}
}
}

1.用空格替换图片标签

a.选择空格符

换行空格:Space键输出的空格,Unicode编码为\u0020,空格前后的内容是允许自动换行的。

不换行空格:Unicode编码为\u00A0,空格前后的内容是不允许自动换行的。

这里看一下两者的效果,如下图。上面的使用普通空格,而下面的使用不换行空格。

 using UnityEngine.UI;
using UnityEngine; [RequireComponent(typeof(Text))]
public class NonBreakingSpaceTextComponent : MonoBehaviour { public static readonly string no_breaking_space = "\u00A0";
protected Text text; void Awake()
{
text = this.GetComponent<Text>();
text.RegisterDirtyVerticesCallback(OnTextChange);
} public void OnTextChange()
{
if (text.text.Contains(" "))
{
text.text = text.text.Replace(" ", no_breaking_space);
}
}
}

显然这里选择不换行空格来进行替换。

b.计算图片所占空格数

首先要知道一个空格所占的宽度,图片的宽度,这样才能算出图片占几个空格,对应的,就是将标签替换为几个空格。

2.换行处理

当图片超过文本框边界时,在空格前插入换行符使图片换行。

3.图片位置计算

图片的位置为这些空格所占位置的中间

4.标签格式简化(待优化)

可以使用如{0},{1}这样的方式来简化图片路径标签,然后读取配置替换为真实的路径。

综上,可以得出如下的代码:

 using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Text;
using UnityEngine.EventSystems;
using System;
using UnityEngine;
using UnityEngine.UI; //图片<icon name=*** w=1 h=1 n=*** p=***/>
//下划线<material=underline c=#ffffff h=1 n=*** p=***>blablabla...</material>
public class RichText2 : Text { private FontData fontData = FontData.defaultFontData; //--------------------------------------------------------图片 start
private static readonly string replaceStr = "\u00A0";
private static readonly Regex imageTagRegex = new Regex(@"<icon name=([^>\s]+)([^>]*)/>");//(名字)(属性)
private static readonly Regex imageParaRegex = new Regex(@"(\w+)=([^\s]+)");//(key)=(value)
private List<RichTextImageInfo> imageInfoList = new List<RichTextImageInfo>();
private bool isImageDirty = false;
//--------------------------------------------------------图片 end protected RichText2()
{
fontData = typeof(Text).GetField("m_FontData", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(this) as FontData;
} readonly UIVertex[] m_TempVerts = new UIVertex[];
protected override void OnPopulateMesh(VertexHelper toFill)
{
if (font == null)
return; // We don't care if we the font Texture changes while we are doing our Update.
// The end result of cachedTextGenerator will be valid for this instance.
// Otherwise we can get issues like Case 619238.
m_DisableFontTextureRebuiltCallback = true; string richText = text;
IList<UIVertex> verts = null;
richText = CalculateLayoutWithImage(richText, out verts); Vector2 extents = rectTransform.rect.size; var settings = GetGenerationSettings(extents);
cachedTextGenerator.Populate(text, settings); Rect inputRect = rectTransform.rect; // get the text alignment anchor point for the text in local space
Vector2 textAnchorPivot = GetTextAnchorPivot(fontData.alignment);
Vector2 refPoint = Vector2.zero;
refPoint.x = Mathf.Lerp(inputRect.xMin, inputRect.xMax, textAnchorPivot.x);
refPoint.y = Mathf.Lerp(inputRect.yMin, inputRect.yMax, textAnchorPivot.y); // Determine fraction of pixel to offset text mesh.
Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint; // Apply the offset to the vertices
//IList<UIVertex> verts = cachedTextGenerator.verts;
float unitsPerPixel = / pixelsPerUnit;
//Last 4 verts are always a new line...
int vertCount = verts.Count - ; toFill.Clear();
if (roundingOffset != Vector2.zero)
{
for (int i = ; i < vertCount; ++i)
{
int tempVertsIndex = i & ;
m_TempVerts[tempVertsIndex] = verts[i];
m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
m_TempVerts[tempVertsIndex].position.x += roundingOffset.x;
m_TempVerts[tempVertsIndex].position.y += roundingOffset.y;
if (tempVertsIndex == )
toFill.AddUIVertexQuad(m_TempVerts);
}
}
else
{
//Debug.Log(unitsPerPixel);
for (int i = ; i < vertCount; ++i)
{
int tempVertsIndex = i & ;
m_TempVerts[tempVertsIndex] = verts[i];
m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
if (tempVertsIndex == )
toFill.AddUIVertexQuad(m_TempVerts);
//Debug.LogWarning(i + "_" + tempVertsIndex + "_" + m_TempVerts[tempVertsIndex].position);
}
}
m_DisableFontTextureRebuiltCallback = false;
} protected string CalculateLayoutWithImage(string richText, out IList<UIVertex> verts)
{
Vector2 extents = rectTransform.rect.size;
var settings = GetGenerationSettings(extents); float unitsPerPixel = / pixelsPerUnit; float spaceWidth = cachedTextGenerator.GetPreferredWidth(replaceStr, settings) * unitsPerPixel; float fontSize2 = fontSize * 0.5f; //解析图片标签,并将标签替换为空格
imageInfoList.Clear();
Match match = null;
StringBuilder builder = new StringBuilder();
while ((match = imageTagRegex.Match(richText)).Success)
{
RichTextImageInfo imageInfo = new RichTextImageInfo();
imageInfo.name = match.Groups[].Value;
string paras = match.Groups[].Value;
if (!string.IsNullOrEmpty(paras))
{
var keyValueCollection = imageParaRegex.Matches(paras);
for (int i = ; i < keyValueCollection.Count; i++)
{
string key = keyValueCollection[i].Groups[].Value;
string value = keyValueCollection[i].Groups[].Value;
imageInfo.SetValue(key, value);
}
}
imageInfo.size = new Vector2(fontSize2 * imageInfo.widthScale, fontSize2 * imageInfo.heightScale);
imageInfo.startVertex = match.Index * ;
int num = Mathf.CeilToInt(imageInfo.size.x / spaceWidth);//占据几个空格
imageInfo.vertexLength = num * ;
imageInfoList.Add(imageInfo); builder.Length = ;
builder.Append(richText, , match.Index);
for (int i = ; i < num; i++)
{
builder.Append(replaceStr);
}
builder.Append(richText, match.Index + match.Length, richText.Length - match.Index - match.Length);
richText = builder.ToString();
} // Populate charaters
cachedTextGenerator.Populate(richText, settings);
verts = cachedTextGenerator.verts;
// Last 4 verts are always a new line...
int vertCount = verts.Count - ; //换行处理
//0 1|4 5|8 9
//3 2|7 6|11 10
//例如前两个字为图片标签,第三字为普通文字;那么startVertex为0,vertexLength为8
for (int i = ; i < imageInfoList.Count; i++)
{
RichTextImageInfo imageInfo = imageInfoList[i];
int startVertex = imageInfo.startVertex;
int vertexLength = imageInfo.vertexLength;
int maxVertex = Mathf.Min(startVertex + vertexLength, vertCount);
//如果最边缘顶点超过了显示范围,则将图片移到下一行
//之后的图片信息中的起始顶点都往后移
if (verts[maxVertex - ].position.x * unitsPerPixel > rectTransform.rect.xMax)
{
richText = richText.Insert(startVertex / , "\r\n");
for (int j = i; j < imageInfoList.Count; j++)
{
imageInfoList[j].startVertex += ;
}
cachedTextGenerator.Populate(richText, settings);
verts = cachedTextGenerator.verts;
vertCount = verts.Count - ;
}
} //计算位置
for (int i = imageInfoList.Count - ; i >= ; i--)
{
RichTextImageInfo imageInfo = imageInfoList[i];
int startVertex = imageInfo.startVertex;
if (startVertex < vertCount)
{
UIVertex uiVertex = verts[startVertex];
Vector2 pos = uiVertex.position;
pos *= unitsPerPixel;
pos += new Vector2(imageInfo.size.x * 0.5f, fontSize2 * 0.5f);
pos += new Vector2(rectTransform.sizeDelta.x * (rectTransform.pivot.x - 0.5f), rectTransform.sizeDelta.y * (rectTransform.pivot.y - 0.5f));
imageInfo.position = pos;
imageInfo.color = Color.white;
}
else
{
imageInfoList.RemoveAt(i);
}
} isImageDirty = true; return richText;
} protected void Update()
{
if (isImageDirty)
{
isImageDirty = false; //回收当前的图片
Image[] images = GetComponentsInChildren<Image>(true);
for (int i = ; i < images.Length; i++)
{
RichTextResourceManager.Instance.SetPoolObject(RichTextResourceType.Image, images[i].gameObject);
} //生成图片
for (int i = ; i < imageInfoList.Count; i++)
{
RichTextImageInfo imageInfo = imageInfoList[i];
var name = imageInfo.name;
var position = imageInfo.position;
var size = imageInfo.size;
var color = imageInfo.color; GameObject go = RichTextResourceManager.Instance.GetPoolObject(RichTextResourceType.Image);
Image image = go.GetComponent<Image>();
RichTextResourceManager.Instance.SetSprite(name, image);
go.transform.SetParent(rectTransform);
go.transform.localScale = Vector3.one;
image.rectTransform.anchoredPosition = position;
image.rectTransform.sizeDelta = size;
image.color = color;
}
}
}
}

效果如下:

[UGUI]图文混排(四):插入图片的更多相关文章

  1. Unity UGUI图文混排源码(一)

    Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...

  2. Unity琐碎(3) UGUI 图文混排解决方案和优化

    感觉使用Unity之后总能看到各种各样解决混排的方案,只能说明Unity不够体恤下情啊.这篇文章主要讲一下个人在使用过程中方案选择和优化过程,已做记录.顺便提下,开源很多意味着坑,还是要开实际需求. ...

  3. Unity UGUI图文混排源码(三) -- 动态表情

    这里是根据图文混排源码(二)进一步修改的,其他链接也不贴了,就贴一个链接就好了,第一次看这文章的同学可以先去看看其他几篇文章 Unity UGUI图文混排源码(二):http://blog.csdn. ...

  4. Unity UGUI图文混排源码(二)

    Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...

  5. Coretext实现图文混排及Gif图片播放

    CoreText是iOS3.2推出的一套文字排版和渲染框架,可以实现图文混排,富文本显示等效果. CoreText中的几个重要的概念:  CTFont CTFontCollection CTFontD ...

  6. Unity UGUI图文混排(七) -- 下划线

    之前更新超链接的时候,忘了搭配实现一个下划线的功能,这篇文章就是来补上这一个功能,时间有点长,一方面没有很好的思路,一方面也没多少时间. 先在网上收集了一下下划线的实现操作,一种是在文本下再创建一个文 ...

  7. [UGUI]图文混排(二):Text源码分析

    UGUI源码: https://bitbucket.org/Unity-Technologies/ui/downloads/?tab=tags 首先下载一份UGUI源码,这里我下载的版本是5.3.2f ...

  8. [UGUI]图文混排(三):资源管理

    1.图文混排中的资源,主要是图片. 2.所谓的资源管理,可以分为资源对象池和资源加载这两部分.这里是为图文混排单独做一套资源管理,当然也可以改为调用项目中的资源管理. RichTextResource ...

  9. Android中Textview显示Html,图文混排,支持图片点击放大

    本文首发于网易云社区 对于呈现Html文本来说,Android提供的Webview控件可以得到很好的效果,但使用Webview控件的弊端是效率相对比较低,对于呈现简单的html文本的话,杀鸡不必使用牛 ...

随机推荐

  1. Hyperledger fabric 1.3版本的安装部署(原创多机多Orderer部署

    首先,我们在安装前,要考虑一个问题 Hyperledger Fabric,通过指定的节点进行背书授权,才能完成交易的存储 延伸开来,就是为了实现容错.高并发.易扩展,需要zookeeper来选择排序引 ...

  2. position实现分层和遮罩层功能

    很多网站,当点了一个按钮后,弹出一个窗口,底层变透明不可选,就是用到层的概念,至少三层 第一层,底层原始层 第二层,遮罩层,用到positon: fixed; top bottom left righ ...

  3. 黄聪:.NET中zip的压缩和解压——SharpCompress

    使用Packaging无法实现通用的zip(使用其他工具压缩)的解压,只支持通过Packaging压缩包zip的解压,而SharpZipLib是基于“GPL”开源方式,风险比较大.在codeplex找 ...

  4. “无法获得锁 /var/lib/dpkg/lock -open (11:资源暂时不可用)”的方法

    另外的ubuntu 问题 在更新的时候有时候会出现 “无法获得锁 /var/lib/dpkg/lock -open (11:资源暂时不可用)”的方法 解决办法: 在ubuntu系统的termial下, ...

  5. ALGO-143_蓝桥杯_算法训练_字符串变换

    问题描述 相信经过这个学期的编程训练,大家对于字符串的操作已经掌握的相当熟练了.今天,徐老师想测试一下大家对于字符串操作的掌握情况.徐老师自己定义了1,,,,5这5个参数分别指代不同的5种字符串操作, ...

  6. window7环境MySql5.7 zip安装配置教程

    1.将zip压缩包解压到一个目录下,并改名为mysql5.7 我的是放在D:\web\mysql5.7下 2.修改my-default.ini文件 下面几项是必填的,否则无法启动 basedir = ...

  7. vue之文本渲染

    Vue使用了基于HTML的模板语法,允许开发者声明式地将DOM绑定至底层Vue实例的数据.所有Vue的模板都是合法的HTML,所以能被遵循规范的浏览器和HTML解析器解析. 在前面,我们一直使用的是{ ...

  8. 云中树莓派(2):将传感器数据上传到 AWS IoT 并利用Kibana进行展示

    云中树莓派(1):环境准备 云中树莓派(2):将传感器数据上传到AWS IoT 并利用Kibana进行展示 1. 传感器安装及配置 1.1 DHT22 安装 DHT22 是一款温度与湿度传感器,它有3 ...

  9. 学习笔记之Visual Studio Code & Clang

    Mac上XCode太占空间,卸载然后安装VSCode和Clang.在VSCode中再安装extension C/C++和Code Runner,配置Tasks: Configure Task,就可以开 ...

  10. es6数组的方法

    1.复习的函数 函数是由关键字function声明的,他是一个引用数据类型,是Function的实例,在调用的时候会开辟一个私有空间 2.函数的成员 arguments:null  (是实参构成的数组 ...