UGUI-图文混排方案

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UGUI-图文混排方案相关的知识,希望对你有一定的参考价值。

参考技术A 1、TextMeshPro
组件直接支持定义emoji和图文混排
优点:
TMP字体的优点(文字干净,渲染效果不受分辨率影响,描边、外发光等文字效果容易实现且性能很好)
不用单独开发,简单易用
缺点:
TMP字体的缺点(离线生成,字符限制,圆角)
目前还有不能支持动画(帧动画和Animation),也不太容易扩展
现在的版本生成的字体库实在太大了,比较全的汉字字库生成TextMeshPro需要的字库之后已经接近17M,如果考虑到游戏中存在2种字体,估计会超过20M的常驻内存在移动端,这个至少现在还很难接受。
文字是序列化,20M的序列化数据,移动端受IO限制,读取时间会有点长。

2、Shader实现
两张纹理(字体纹理和emoji纹理)根据当前顶点是属于文字 or 图片来选择采样,需要uv0和uv1两套uv,需要顶点数据传递一个标志来区分文字和图片
优点:
文本(字体相同)和图片可以在一个drawcall渲染
比较容易做帧动画
缺点:
与Outline、Shadow等组件不友好(对图片也应用了效果)(需要定制开发)
对所有UIBaseEffect子类都需要区分顶点是文本还是图片
无法对文本和图片单独做Animation

3、Text组件 + Image组件 + Layout
用Text组件和Image组件组合,用Layout来控制组件位置
优点:
简单粗暴,容易实现
容易做帧动画和Animation
Text和Image都是UGUI,和其他UI容易合并drawcall
缺点:
会生成很多组件,在配合List滑动等功能时,可能会导致GC的问题(可用对象池优化)
ui rebuild会非常严重,特别是有动画的情况下,layout也可能会一直持续rebuild
基于layout本身的规则,位置不好定制

4、Text组件 + Sprite组件 + Layout
用Text组件和Image组件组合,用Layout来控制组件位置
优点:
简单粗暴,容易实现
容易做帧动画和Animation
Sprite本身不是UGUI,不会引起UI的rebuild
缺点:
会生成很多组件,在配合List滑动等功能时,可能会导致GC的问题(可用对象池优化),rebuild也会有点问题。
Sprite脱离了UI,不能和UI合批,可动态合批。和UI有遮挡关系时,层级可能会增加drawcall
基于layout本身的规则,位置不好定制

5、Text组件 + 图片
与3、4方案的不同是位置计算,在Text中遇到图片就留出"合适的空间",这样文本可用一个组件搞定。但位置计算比较麻烦一些。

6、Text组件的富文本
UGUI富文本有一个<quad/>标签,它可作为一个占位符号,在Unity底层会为<quad/>标签生成顶点数据(两个三角形),在上层根据标签所在位置拿到相应的顶点数据,把顶点信息转换到世界空间,然后在另一个图片组件中去渲染(取出的顶点数据本地空间-世界空间-本地空间),并设置好位置。
注意点:
Text组件没有自动换行时,富文本的标签不会生成顶点数据,有自动换行时,富文本标签会生成无用的顶点数据,两种情况下索引偏移不一样。

[UGUI]图文混排:标签制定和解析

参考链接:

https://github.com/SylarLi/RichText/tree/master/Assets/Scripts

正则表达式:

https://blog.csdn.net/lyh916/article/details/49201195

 

图文混排主要用于聊天,其实就是传输某种格式的字符串,然后解析这个字符串,生成表情文字等。图文混排的第一步,就是确定好格式,这里使用html的标签格式,对于代码中出现的start和end字段可以先忽略。标签格式如下:

<material=underline c=#ffffff h=1 n=*** p=***>blablabla...</material>

 

RichTextTag.cs

 1 //标签类型
 2 public enum RichTextTagType
 3 {
 4     None,
 5     Underline,      //下划线
 6 }
 7 
 8 //标签基类
 9 public abstract class RichTextTag
10 {
11     public int start;
12     public int end;
13     public abstract RichTextTagType tagType { get; }
14 
15     public abstract void SetValue(string key, string value);
16 }

 

RichTextUnderlineTag.cs

 1 using UnityEngine;
 2 
 3 //下划线标签
 4 public class RichTextUnderlineTag : RichTextTag {
 5 
 6     public Color color = Color.white;//颜色
 7     public float height = 1f;//高度
 8     public string eventName;//事件名
 9     public string eventParameter;//事件参数
10 
11     public override RichTextTagType tagType { get { return RichTextTagType.Underline; } }
12 
13     public override void SetValue(string key, string value)
14     {
15         switch (key)
16         {
17             case "c":
18                 {
19                     ColorUtility.TryParseHtmlString(value, out color);
20                     break;
21                 }
22             case "h":
23                 {
24                     float.TryParse(value, out height);
25                     break;
26                 }
27             case "n":
28                 {
29                     eventName = value;
30                     break;
31                 }
32             case "p":
33                 {
34                     eventParameter = value;
35                     break;
36                 }
37             default:
38                 break;
39         }
40     }
41 }

 

RichTextTagParser.cs

 1 using System.Text.RegularExpressions;
 2 
 3 //解析一条标签:<material xxx>
 4 public class RichTextTagParser {
 5 
 6     private static readonly Regex tagRegex = new Regex(@"<material=([^>s]+)([^>]*)>");//(标签类型)(标签参数)
 7     private static readonly Regex paraRegex = new Regex(@"(w+)=([^s]+)");//(key)=(value)
 8     public string content;//<material=xxx xxx>
 9     public int start;
10     public int end;
11 
12     public RichTextTag Parse()
13     {
14         RichTextTag tag = null;
15         Match match = tagRegex.Match(content);
16         if (match.Success)
17         {
18             string tagName = match.Groups[1].Value;//标签类型
19             if (!tagName.StartsWith("#"))
20             {
21                 var keyValueCollection = paraRegex.Matches(match.Groups[2].Value);//标签参数
22                 switch (tagName)
23                 {
24                     case "underline":
25                         {
26                             tag = new RichTextUnderlineTag();
27                             break;
28                         }
29                     default:
30                         break;
31                 }
32                 if (tag != null)
33                 {
34                     tag.start = start;
35                     tag.end = end;
36                     for (int i = 0; i < keyValueCollection.Count; i++)
37                     {
38                         string key = keyValueCollection[i].Groups[1].Value;
39                         string value = keyValueCollection[i].Groups[2].Value;
40                         tag.SetValue(key, value);
41                     }
42                 }
43             }
44         }
45         return tag;
46     }
47 }

 

RichTextParser.cs

 1 using System.Collections.Generic;
 2 using System.Text.RegularExpressions;
 3 
 4 //解析全部标签
 5 public class RichTextParser {
 6 
 7     private static readonly Regex regex = new Regex(@"</*material[^>]*>");//<material xxx> or </material>
 8     private const string endStr = "</material>";
 9 
10     private Stack<RichTextTagParser> tagParserStack;
11     private List<RichTextTag> tagList;
12 
13     public RichTextParser()
14     {
15         tagParserStack = new Stack<RichTextTagParser>();
16         tagList = new List<RichTextTag>();
17     }
18 
19     public void Parse(string richText, out List<RichTextTag> tags)
20     {
21         tagParserStack.Clear();
22         tagList.Clear();
23         Match match = regex.Match(richText);
24         while (match.Success)
25         {
26             if (match.Value == endStr)
27             {
28                 if (tagParserStack.Count > 0)
29                 {
30                     RichTextTagParser tagParser = tagParserStack.Pop();
31                     tagParser.end = match.Index - 1;
32                     if (tagParser.end >= tagParser.start)
33                     {
34                         RichTextTag tag = tagParser.Parse();
35                         if (tag != null)
36                         {
37                             tagList.Add(tag);
38                         }
39                     }
40                 }
41             }
42             else
43             {
44                 RichTextTagParser tagParser = new RichTextTagParser();
45                 tagParser.content = match.Value;
46                 tagParser.start = match.Index + match.Length;
47                 tagParserStack.Push(tagParser);
48             }
49             match = match.NextMatch();
50         }
51         tags = tagList;
52     }
53 }

 

测试如下:

 1 using UnityEngine;
 2 using System.Collections.Generic;
 3 
 4 //下划线<material=underline c=#ffffff h=1 n=*** p=***>blablabla...</material>
 5 public class RichTextTest : MonoBehaviour {
 6 
 7     private string a = @"123<material=underline c=#ff0000 h=1 n=name1 p=para1>blablabla...</material>qwe" +
 8         @"<material=underline c=#00ff00 h=2 n=name2 p=para2>blablabla...</material>asd";
 9     private List<RichTextTag> tagList;
10 
11     private void Start()
12     {
13         RichTextParser parser = new RichTextParser();
14         parser.Parse(a, out tagList);
15         for (int i = 0; i < tagList.Count; i++)
16         {
17             RichTextUnderlineTag tag = tagList[i] as RichTextUnderlineTag;
18             Debug.Log(tag.color);
19             Debug.Log(tag.height);
20             Debug.Log(tag.eventName);
21             Debug.Log(tag.eventParameter);
22         }
23     }
24 }

 

结果:

技术分享图片

以上是关于UGUI-图文混排方案的主要内容,如果未能解决你的问题,请参考以下文章

[UGUI]图文混排:标签制定和解析

[UGUI]图文混排:下划线

iOS 表情键盘+gif聊天图文混排,看我的就够了

[UGUI]图文混排:添加下划线

ios开发,关于图文混排

ios开发,关于图文混排