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-图文混排方案的主要内容,如果未能解决你的问题,请参考以下文章