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

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

为了方便整理,申请了一个专栏,链接:Unity UGUI图文混排专栏

图文混排解决方案二:

通过继承Text组件来获取文字的UIVertex并得到他的位置,通过Text富文本的<quad />来为图片占位,这样来实现图文混排,这里参考了一篇博客:http://blog.csdn.net/akof1314/article/details/49028279

1.这里我们会使用到一个SpriteAsset,具体的创建方法:http://blog.csdn.net/qq992817263/article/details/50958025

2.自定义一个渲染组件,用来渲染图片,后面我会将他放在Text文本下,这里会用一个参数,就是上面的SpriteAsset文件,具体代码如下

using UnityEngine;
using UnityEngine.UI;
using System.Collections; public class SpriteGraphic : MaskableGraphic {
    public SpriteAsset m_spriteAsset;     public override Texture mainTexture
    {
        get
        {
            if (m_spriteAsset == null)
                return s_WhiteTexture;             if (m_spriteAsset.texSource == null)
                return s_WhiteTexture;
            else
                return m_spriteAsset.texSource;
        }
    } #if UNITY_EDITOR
    //在编辑器下 
    protected override void OnValidate()
    {
        base.OnValidate();
        //Debug.Log("Texture ID is " + this.texture.GetInstanceID());
    }
#endif     protected override void OnRectTransformDimensionsChange()
    {
        // base.OnRectTransformDimensionsChange();
    }     /// <summary>
    /// 绘制后 需要更新材质
    /// </summary>
    public new void UpdateMaterial()
    {
        base.UpdateMaterial();
    }
}

3.自定义一个脚本用来继承Text,这里就是一个较为核心的代码,里面写了较为详细的注释

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Text.RegularExpressions; public class InlieText : Text {     /// <summary>
    /// 用正则取标签属性 名称-大小-宽度比例
    /// </summary>
    private static readonly Regex m_spriteTagRegex =
          new Regex(@"<quad name=(.+?) size=(\d*\.?\d+%?) width=(\d*\.?\d+%?) />", RegexOptions.Singleline);
    /// <summary>
    /// 需要渲染的图片信息列表
    /// </summary>
    private List<InlineSpriteInfor> listSprite;
    /// <summary>
    /// 图片资源
    /// </summary>
    private SpriteAsset m_spriteAsset;
    /// <summary>
    /// 标签的信息列表
    /// </summary>
    private List<SpriteTagInfor> listTagInfor;
    /// <summary>
    /// 图片渲染组件
    /// </summary>
    private SpriteGraphic m_spriteGraphic;
    /// <summary>
    /// CanvasRenderer
    /// </summary>
    private CanvasRenderer m_spriteCanvasRenderer;     /// <summary>
    /// 初始化 
    /// </summary>
    protected override void OnEnable()
    {
        base.OnEnable();
        if (m_spriteGraphic == null)
            m_spriteGraphic = GetComponentInChildren<SpriteGraphic>();
        if (m_spriteCanvasRenderer == null)
            m_spriteCanvasRenderer = m_spriteGraphic.GetComponentInChildren<CanvasRenderer>();
        m_spriteAsset = m_spriteGraphic.m_spriteAsset;
    }     /// <summary>
    /// 在设置顶点时调用
    /// </summary>
    public override void SetVerticesDirty()
    {
        base.SetVerticesDirty();
        //解析标签属性
        listTagInfor = new List<SpriteTagInfor>();
        foreach (Match match in m_spriteTagRegex.Matches(text))
        {
            SpriteTagInfor tempSpriteTag = new SpriteTagInfor();
            tempSpriteTag.name = match.Groups[1].Value;
            tempSpriteTag.index = match.Index;
            tempSpriteTag.size = new Vector2(float.Parse(match.Groups[2].Value)*float.Parse(match.Groups[3].Value), float.Parse(match.Groups[2].Value));
            listTagInfor.Add(tempSpriteTag);
        }
    }     /// <summary>
    /// 绘制模型
    /// </summary>
    /// <param name="toFill"></param>
    protected override void OnPopulateMesh(VertexHelper toFill)
    {
        base.OnPopulateMesh(toFill);
        //获取所有的UIVertex,绘制一个字符对应6个UIVertex,绘制顺序为012 203
        List<UIVertex> listUIVertex = new List<UIVertex>();
        toFill.GetUIVertexStream(listUIVertex);
        
        //通过标签信息来设置需要绘制的图片的信息
        listSprite = new List<InlineSpriteInfor>();
        for (int i = 0; i < listTagInfor.Count; i++)
        {
            //UGUIText不支持<quad/>标签,表现为乱码,我这里将他的uv全设置为0,清除乱码
            for (int m = listTagInfor[i].index*6; m < listTagInfor[i].index*6 + 6; m++)
            {
                UIVertex tempVertex = listUIVertex[m];
                tempVertex.uv0 = Vector2.zero;
                listUIVertex[m] = tempVertex;
            }             InlineSpriteInfor tempSprite = new InlineSpriteInfor();
            //如果图片在第一个位置,则计算他的位置为文本的初始点位置
            //否,则返回上一个字符的第三个UIVertex的position,这是根据他的顶点的绘制顺序所获得的
            if (listTagInfor[i].index == 0)
            {
                Vector2 anchorPivot = GetTextAnchorPivot(alignment);
                Vector2 rectSize = rectTransform.sizeDelta;
                
                tempSprite.textpos = -rectSize / 2.0f + new Vector2(rectSize.x * anchorPivot.x,rectSize.y*anchorPivot.y- listTagInfor[i].size.y);             }
            else
                tempSprite.textpos = listUIVertex[listTagInfor[i].index * 6 - 4].position;
            
            //设置图片的位置
            tempSprite.vertices = new Vector3[4];
            tempSprite.vertices[0] = new Vector3(0, 0, 0) + tempSprite.textpos;
            tempSprite.vertices[1] = new Vector3(listTagInfor[i].size.x, listTagInfor[i].size.y, 0) + tempSprite.textpos;
            tempSprite.vertices[2] = new Vector3(listTagInfor[i].size.x, 0, 0) + tempSprite.textpos;
            tempSprite.vertices[3] = new Vector3(0, listTagInfor[i].size.y, 0) + tempSprite.textpos;             //计算其uv
            Rect spriteRect = m_spriteAsset.listSpriteInfor[0].rect;
            for (int j = 0; j < m_spriteAsset.listSpriteInfor.Count; j++)
            {
                //通过标签的名称去索引spriteAsset里所对应的sprite的名称
                if (listTagInfor[i].name == m_spriteAsset.listSpriteInfor[j].name)
                    spriteRect = m_spriteAsset.listSpriteInfor[j].rect;
            }
            Vector2 texSize = new Vector2(m_spriteAsset.texSource.width, m_spriteAsset.texSource.height);             tempSprite.uv = new Vector2[4];
            tempSprite.uv[0] = new Vector2(spriteRect.x / texSize.x, spriteRect.y / texSize.y);
            tempSprite.uv[1] = new Vector2((spriteRect.x + spriteRect.width) / texSize.x, (spriteRect.y + spriteRect.height) / texSize.y);
            tempSprite.uv[2] = new Vector2((spriteRect.x + spriteRect.width) / texSize.x, spriteRect.y / texSize.y);
            tempSprite.uv[3] = new Vector2(spriteRect.x / texSize.x, (spriteRect.y + spriteRect.height) / texSize.y);
            
            //声明三角顶点所需要的数组
            tempSprite.triangles = new int[6];
            listSprite.Add(tempSprite);
        }
        //清除<quad />标签的乱码 重新绘制
        toFill.Clear();
        toFill.AddUIVertexTriangleStream(listUIVertex);
        DrawSprite();
    }    /// <summary>
   /// 绘制图片
   /// </summary>
    void DrawSprite()
    {
        Mesh m_spriteMesh = new Mesh();         List<Vector3> tempVertices = new List<Vector3>();
        List<Vector2> tempUv = new List<Vector2>();
        List<int> tempTriangles = new List<int>();
        
        for (int i = 0; i < listSprite.Count; i++)
        {
            for (int j = 0; j < listSprite[i].vertices.Length; j++)
            {
                tempVertices.Add(listSprite[i].vertices[j]);
            }
            for (int j = 0; j < listSprite[i].uv.Length; j++)
            {
                tempUv.Add(listSprite[i].uv[j]);
            }
            for (int j = 0; j < listSprite[i].triangles.Length; j++)
            {
                tempTriangles.Add(listSprite[i].triangles[j]);
            }
        }
        //计算顶点绘制顺序
        for (int i = 0; i < tempTriangles.Count; i++)
        {
            if (i % 6 == 0)
            {
                int num = i / 6;
                tempTriangles[i] = 0 + 4 * num;
                tempTriangles[i + 1] = 1 + 4 * num;
                tempTriangles[i + 2] = 2 + 4 * num;                 tempTriangles[i + 3] = 1 + 4 * num;
                tempTriangles[i + 4] = 0 + 4 * num;
                tempTriangles[i + 5] = 3 + 4 * num;
            }
        }         m_spriteMesh.vertices = tempVertices.ToArray();
        m_spriteMesh.uv = tempUv.ToArray();
        m_spriteMesh.triangles = tempTriangles.ToArray();         if (m_spriteMesh == null)
            return;         m_spriteCanvasRenderer.SetMesh(m_spriteMesh);
        m_spriteGraphic.UpdateMaterial();
    } } [System.Serializable]
public class SpriteTagInfor
{
    /// <summary>
    /// sprite名称
    /// </summary>
    public string name;
    /// <summary>
    /// 对应的字符索引
    /// </summary>
    public int index;
    /// <summary>
    /// 大小
    /// </summary>
    public Vector2 size;
} [System.Serializable]
public class InlineSpriteInfor
{
    // 文字的最后的位置
    public Vector3 textpos;
    // 4 顶点 
    public Vector3[] vertices;
    //4 uv
    public Vector2[] uv;
    //6 三角顶点顺序
    public int[] triangles;
}

4.开始测试效果,创建一个InlieText组件,并在其组件下,添加一个SpriteGraphic组件,输入文字加标签测试

InlieTex组件:

SpriteGraphic组件:

文字测试:

5.做了一个聊天测试:

6.同时在测试的时候就发现了些许bug,这里并不想写出来,有兴趣的可以一起修改讨论。

工程使用的unity版本为unity的版本为:5.3.1f1

最后给出工程链接:https://code.csdn.net/qq992817263/uguitextpro/tree/master

Unity UGUI图文混排源码(二)的更多相关文章

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

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

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

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

  3. Unity UGUI图文混排源码(四) -- 聊天气泡

    这里有同学建议在做聊天气泡时,可以更改为一张图集对应多个Text,这样能节省资源,不过我突然想到每个Text一个图集,可以随时更换图集,这样表情图更丰富一些,于是我就先将现有的聊天demo改为了聊天气 ...

  4. Unity UGUI图文混排(六) -- 超链接

    图文混排更新到超链接这儿,好像也差不多了,不过就在最后一点,博主也表现得相当不专业,直接整合了山中双木林同学提供的超链接的解决方案,博主甚至没来得及细看就直接复制了,但感觉还是挺好用的. 博主已经将超 ...

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

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

  6. Unity UGUI图文混排(五) -- 一张图集对应多个Text

    继上一篇说的更新了一张图集对应多个Text的功能,为了节省资源嘛 这里,但是也没有舍弃之前的一个Text一个图集,因为我感觉应该两个都有用,于是我重新写了一个脚本 1.其实大体跟前面的都没变,解析标签 ...

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

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

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

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

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

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

随机推荐

  1. MAX(字段)加0与不加0的测试

    --max(字段名)中的"字段名"的数据类型是字符型的,"字段名"+ 0后,oracle会隐式的转换成数字型 --测试 )); insert into Test ...

  2. Python List insert()方法详解

    1.功能insert()函数用于将指定对象插入列表的指定位置. 2.语法list.insert(index, obj) 3.参数index: 对象obj需要插入的索引位置.obj: 插入列表中的对象. ...

  3. Web缓存(一) - HTTP协议缓存

    为什么要使用 Web 缓存 Web缓存一般分为浏览器缓存.代理服务器缓存以及网关缓存,本文主要讲的是 浏览器缓存,其它两种缓存大家自行去了解下. Web 缓存游走于服务器和客户端之间.这个服务器可能是 ...

  4. ACM Ignatius and the Princess II

    Problem Description Now our hero finds the door to the BEelzebub feng5166. He opens the door and fin ...

  5. zookeeper基本原理及适用场景 转:http://blog.chinaunix.net/uid-26748613-id-4536290.html

    1.1 zookeeper简介 Zookeeper 是 Hadoop 生态系统中的协同实现,是Hadoop集群管理的一个必不可少的模块,它主要来控制集群中的数据,如它管理Hadoop集群中的NameN ...

  6. ViewPager滑动后,可移动的Imageview会回到初始化的位置

    知乎看到的原文http://www.zhihu.com/question/37398770?sort=created ViewPager滑动后,可移动的Imageview会回到初始化的位置? < ...

  7. NLP系列(1)_从破译外星人文字浅谈自然语言处理基础

    作者:龙心尘 &&寒小阳 时间:2016年1月. 出处: http://blog.csdn.net/longxinchen_ml/article/details/50543337 ht ...

  8. Linux 高性能服务器编程——IP协议详解

    1 IP服务特点 IP协议是TCP/IP协议族的动力,它为上层协议提供无状态.无连接.不可靠的服务. 无状态:IP通信双方不同步传输数据的状态信息,因此IP数据包的发送.传输和接收都是无序的.     ...

  9. [ExtJS5学习笔记]第二十一节 Extjs5中使用config配置给ext.widget或者create方法传递参数

    本文地址:http://blog.csdn.net/sushengmiyan/article/details/39252805 官方例子:http://docs.sencha.com/extjs/5. ...

  10. GCD API 理解 (一)

    资料先行 GCD 深入理解:第一部分 GCD 深入理解:第二部分 以上两篇文章是关于GCD讲的比较好的文章,翻译自raywenderlich,该网站有很多关于iOS 开发的优秀文章. 引子 iOS 开 ...