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. sourceTree+gerrit管理代码

    第一次接触gerrit,会对这种代码管理方式非常排斥,尤其是习惯了用sourceTree配合git进行代码管理的同学.不爽归不爽,代码还得写,我们的目标是让开发过程爽起来. 关于gerrit的知识,移 ...

  2. Oracle中SQL语句分类

    Oracle中SQL语句分类如下:1.DML语句 insert/delete/update/select/merge/explan plan/lock table2.DDL语句 create/atlt ...

  3. python学习之路网络编程篇(第三篇)

    python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. #!/usr/bin/env python # -*- coding:utf-8 -*- import t ...

  4. MySQL系列教程(三)

    mySQL集群(cluster) 这一章,我根本不打算写,因为mySQL 的 官方Cluster方案基本上都是bullshit,尤其是它的官方集群方案,竟然都无人维护了,而且mySQL集群完全可以用眼 ...

  5. [Matlab+C/C++] 读写二进制文件

    introduction 因为Matlab操作简单.方便,它被应用于很多领域:音频处理,图像处理,数值计算等.尽管MATLAB容易操作,但受限于他的语言解释机制,MATLAB的执行速度通常较低.C/C ...

  6. APP自动化框架LazyAndroid使用手册(4)--测试模板工程详解

    概述 前面的3篇博文分别对lazyAndroid的框架简介.元素抓取和核心API进行了说明,本文将基于框架给出的测试模板工程,详细阐述下使用该框架进行安卓UI自动化测试的步骤. 模板工程 先来看一下模 ...

  7. Dubbo框架应用之(四)--Dubbo基于Zookeeper实现分布式实例

    上三篇文章主要是解决了概念性的补充和学习,充分结合实战来深入理解 入门实例解析 第一:provider-提供服务和相应的接口 创建DemoService接口 package com.unj.dubbo ...

  8. Python+Tkinter 密保小工具

    上图 代码 核心 编解码方面 Tkinter界面更新 总结 昨天被一同学告知,网上的一个QQ密码库中有我的一条记录,当时我就震惊了,赶紧换了密码.当然了,这件事也给了我一个警示,那就是定期的更换自己的 ...

  9. Node.js 撸第一个Web应用

    使用Node.js 创建Web 应用与使用PHP/Java 语言创建Web应用略有不同. 使用PHP/Java 来编写后台代码时,需要Apache 或者 Nginx 的HTTP 服务器,而接受请求和提 ...

  10. Dynamics CRM2013/2015 检索实体属性的两种方式

    昨天有朋友问起如何查询一个字段属性是否存在于某个实体中,一般这个问题我们会采取最直观的查询方式即MetadataBrowser,该工具是一个zip解决方案包在SDK中的如下目录内"\SDK\ ...