TextMeshPro图文混排的两种实现方式,不打图集

TMP图文混排

    • 方案一:TMP自带图文混排
      • 使用方法
        • 打包图集
        • 使用
    • 方案二:不打图集,可以使用任何图片

接到一个需求,TextMeshPro 图文混排。

方案一:TMP自带图文混排

优点布局适应优秀,字体左中右布局位置都很不错
缺点用到的图片需要打包,使用Resources加载

使用方法

打包图集

打包图集这里推荐使用TexturePacker工具,功能强大,完美适配。这个软件也可以用于压缩图集。

TexturePacker链接

1.将你需要的散图或文件夹拖到这个区域,或使用添加精灵按钮添加。

2.选中下图按钮,选择Json(Array), 注意是Array。
下面的图片模式和打包可以自己尝试,主要是控制压缩和图片格式,这里不做介绍。

3.点击发布,获得一个Json文件和一张PNG,Json 是PNG各个图片的位置信息。

4.将上一步的资源导入Unity,然后打开TextMeshPro的图集工具 Sprite Importer。

5.将Json 和PNG 拖入下图中对应的位置。点击生成,然后存储到自己的文件夹

使用

1.将生成的图集拖入TMP的Sprite Asset中,使用图片时,在字符串中插入<sprite=你的图片id>,例如图中“<sprite=0> 图片好看吗”

2. ??? 图片咋这样??? ,发现图片大小不对,被勾选了自动转变为2的n次方。这里改成None ,图片能完整显示了

3. 还是不对,位置偏差好多,按下图2修改X和Y的偏移,最下方的Global Offset 是同时修改所有图片

完成啦,撒花~~

方案二:不打图集,可以使用任何图片

优点当你有大量图片都可能用于图文混排,不方便打包时使用。代码没多少,随便修随便改- -
缺点对布局适配一般,只支持了整个组件的对齐,文字只支持了左对齐

原理就是将含图片的文本拆分成几段文本和图片的组合,计算位置,使用多个TMP和图片拼接
图片暂定格式 [img] 图片ID[/img]

using System.Collections.Generic;
using System.Text.RegularExpressions;
using TMPro;
using UnityEngine;
using UnityEngine.UI;public class TextImageView : MonoBehaviour
{public enum TextImageAlignmentH{Left,Center,Right}public enum TextImageAlignmentV{Top,Center,Bottom}public Transform content;public int FontSize;public float maxWidth;public TextMeshProUGUI tmp;public Image img;public TextImageAlignmentH alignmentH = TextImageAlignmentH.Center;public TextImageAlignmentV alignmentV = TextImageAlignmentV.Center;private float _lineHeight;private float _averageWidth;private float _maxLength;private List<KeyValuePair<string, int>> _contentList = new List<KeyValuePair<string, int>>();public string text{set { Test(value); }}public void Test(string text){_contentList = StringToKeyValuePair(text);var reduceWidth = 0f;var height = 0f;tmp.fontSize = FontSize;tmp.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, maxWidth);tmp.gameObject.SetActive(true);tmp.text = "test";tmp.ForceMeshUpdate();_lineHeight = tmp.textInfo.lineInfo[0].lineHeight;tmp.gameObject.SetActive(false);content.DestroyChildren();for (var i = 0; i < _contentList.Count; i++){if (_contentList[i].Value == 0){var label = TestText(_contentList[i].Key, reduceWidth,height);for (var i1 = 0; i1 < label.textInfo.lineInfo.Length; i1++){var lineInfo = label.textInfo.lineInfo[i1];var width = lineInfo.length;if(_maxLength < width){_maxLength = width;}if(i1 == label.textInfo.lineCount - 1){height = (label.transform.localPosition.y - i1*_lineHeight);reduceWidth = maxWidth - width - 5;}}}else{var imgData = TestImage(_contentList[i].Key, reduceWidth, height);reduceWidth = imgData.reduce + 5;if (_maxLength < (maxWidth - imgData.reduce)){_maxLength = maxWidth - imgData.reduce;}if(imgData.changeLine){height -= _lineHeight;}}}height -= _lineHeight;var x = 0f;switch (alignmentH){case TextImageAlignmentH.Left:x = 0;break;case TextImageAlignmentH.Center:x = (maxWidth - _maxLength) / 2;break;case TextImageAlignmentH.Right:x = maxWidth - _maxLength;break;}var y = 0f;switch (alignmentV){case TextImageAlignmentV.Top:y = _lineHeight;break;case TextImageAlignmentV.Center:y = -height/2 +_lineHeight/2;break;case TextImageAlignmentV.Bottom:y = -height;break;}content.transform.localPosition = new Vector3(x,y,0);}// <color=#FFFFFF><sprite=1/> 计分时\n<color=#FF0000>+4 </color>倍率</color>private List<KeyValuePair<string, int>> StringToKeyValuePair(string text){var result = new List<KeyValuePair<string, int>>();// 拆分字符串,匹配图片名和文字内容var splitText = Regex.Split(text, @"(\[img\]|\[/img\])");// 遍历拆分后的字符串for (var i = 0; i < splitText.Length; i++){switch (splitText[i]){case "[img]":{// 如果是图片名,将它加入结果列表result.Add(new KeyValuePair<string, int>(splitText[i + 1], 1));// 跳过处理下一个字符串i++;}continue;case "[/img]":// 如果是 [/img] ,跳过处理下一个字符串continue;default:{var content = splitText[i];if (string.IsNullOrEmpty(content)){continue;}result.Add(new KeyValuePair<string, int>(content, 0));}break;}}return result;}public string testValue;[ContextMenu("测试")]public void Test1(){// TestText(testValue, 300,0);Test(testValue);}private TextMeshProUGUI TestText(string value,float reduceWidth,float height){var obj = GameObject.Instantiate((UnityEngine.Object)tmp.gameObject) as GameObject;//GameObject obj = null;if (obj == null){return null;}obj.SetActive(true);if(_averageWidth == 0){_averageWidth = obj.GetComponent<TextMeshProUGUI>().GetPreferredValues(value).x/ value.Length;}var label = obj.GetComponent<TextMeshProUGUI>();label.fontSize = FontSize;label.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, maxWidth); obj.transform.SetParent(content);obj.transform.localScale = Vector3.one;if (reduceWidth <= _averageWidth)//剩下的空间不够一个字,直接换行{obj.transform.localPosition = new Vector3(0, height - _lineHeight, 0);}else{value = $"<space={maxWidth - reduceWidth}>{value}"; // 创建新字符串obj.transform.localPosition = new Vector3(0, height, 0); }value = DelUrlFlag(value);label.text = value;label.ForceMeshUpdate();return label; // 计算剩余宽度}private (bool changeLine,float reduce) TestImage(string value,float reduceWidth,float height){var obj = GameObject.Instantiate((UnityEngine.Object)img.gameObject) as GameObject;if (obj == null){return (false,reduceWidth);}obj.SetActive(true);var sp = obj.GetComponent<Image>();sp.SetIcon(int.Parse(value));//value是图片的ID,这里替换为自己的设置图片的方法var tempHeight = _lineHeight ;sp.SetNativeSize();var size = sp.rectTransform.sizeDelta;var rate = size.y / tempHeight;sp.rectTransform.sizeDelta = new Vector2(size.x / rate, tempHeight);var needWidth = sp.rectTransform.sizeDelta.x;obj.transform.SetParent(content);obj.transform.localScale = Vector3.one;if (needWidth > reduceWidth){obj.transform.localPosition = new Vector3(-maxWidth/2 +needWidth/2, height - _lineHeight, 0);return (true,maxWidth -needWidth);}else{obj.transform.localPosition = new Vector3(-maxWidth/2 + (maxWidth - reduceWidth)+needWidth/2, height, 0);return (false,reduceWidth - needWidth);}}private string DelUrlFlag(string strTxt){strTxt = strTxt.Replace("[/url]", "");int nStartLeftBracket = 0;int nStartRightBracket = 0;while (true){nStartLeftBracket = strTxt.IndexOf('[', nStartLeftBracket);nStartRightBracket = strTxt.IndexOf(']', nStartRightBracket);if (nStartLeftBracket > -1 && nStartRightBracket > -1 && nStartRightBracket > nStartLeftBracket){string sub = strTxt.Substring(nStartLeftBracket, nStartRightBracket - nStartLeftBracket + 1);if (sub.Contains("url")){strTxt = strTxt.Remove(nStartLeftBracket, nStartRightBracket - nStartLeftBracket + 1);nStartLeftBracket = 0;nStartRightBracket = 0;}else{nStartLeftBracket = nStartRightBracket;nStartRightBracket += 1;}}else{break;}}return strTxt;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/770157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web常见标签属性

应用软件&#xff1a;c/s&#xff08;客户端与服务端&#xff09; b/s&#xff08;服务器与浏览器架构&#xff09;web前端&#xff1a;html5、css3、JavaScriptHtml5&#xff1a;超文本标记语言 超链接标签 语法规范<标签名> marquee 标签之间可以嵌套属性&#xff1a;…

【项目】均衡代码评测

TOC 目录 项目介绍 开发环境 主要技术 项目实现 公共模块 日志 工具类 编译运行模块 介绍 编译 运行 编译和运行结合起来 业务逻辑模块 介绍 MVC模式框架 模型&#xff08;Model&#xff09; 视图&#xff08;View) 控制器&#xff08;Controller&#xff09…

使用html做一个2048小游戏

下载地址: https://pan.xunlei.com/s/VNtiF13HxmmE4gglflvS1BUhA1?pwdvjrt# 提取码&#xff1a;vjrt”

Linux文件系统 底层原理

linux文件、目录、Inode inode负责文件的元数据和数据存储&#xff0c;文件存储块负责实际数据的存储&#xff0c;而目录文件维护文件名和inode之间的联系。 1. 用户空间到内核空间 首先&#xff0c;当用户程序请求打开一个文件时&#xff08;例如使用open系统调用&#xff09…

Excel 打开后提示:MicrosoftExcel无法计算某个公式。在打开的工作簿中有一个循环引用...

目录预览 一、问题描述二、原因分析三、解决方案四、参考链接 一、问题描述 MicrosoftExcel无法计算某个公式。在打开的工作簿中有一个循环引用&#xff0c;但无法列出导致循环的引I用。请尝试编辑上次输入的公式&#xff0c;或利用“撤消”命令删除该公式&#xff0c;如下图&…

微服务(基础篇-003-Nacos)

目录 Nacos注册中心&#xff08;1&#xff09; 认识和安装Nacos&#xff08;1.1&#xff09; Nacos快速入门&#xff08;1.2&#xff09; 服务注册到Nacos(1.2.1) Nacos服务分级存储模型&#xff08;1.3&#xff09; 配置集群&#xff08;1.3.1&#xff09; 根据集群修改…

如何用Airtest脚本连接无线Android设备?

之前我们已经详细介绍过如何用AirtestIDE无线连接Android设备&#xff0c;它的关键点在于&#xff0c;需要先 adb connect 一次&#xff0c;才能点击 connect 按钮无线连接上该设备&#xff1a; 但是有很多同学&#xff0c;在使用纯Airtest脚本的形式连接无线设备时&#xff0c…

K8s-网络原理-下篇

引言 本文是《深入剖析 K8s》的学习笔记&#xff0c;相关图片和案例可从https://github.com/WeiXiao-Hyy/k8s_example中获取&#xff0c;欢迎Star! K8s 的网络隔离: NetWorkPolicy K8s 如何考虑容器之间网络的“隔离” -> NetWorkPolicy 以下是一个 NetWorkPolicy 的定义…

Android开发 --- Android12外部存储权限问题

1.问题 Android12使用如下权限&#xff0c;将不会获得读写文件的权限 <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE" /> 2.解决 if (!Environment.isExternalStorageManager()) {Intent intent new Intent(Settings.ACTION_M…

将数据转换成xml格式的文档并下载

现在有一个实体类对象的集合&#xff0c;需要将它们转换为xml文档&#xff0c;xml文档就是标签集合的嵌套&#xff0c;例如一个学生类&#xff0c;有姓名、年龄等&#xff0c;需要转换成一下效果&#xff1a; <student><age>14</age><name>张三</na…

Java学习Day3

一道简单练习题&#xff0c;对编号进行随机排名 import java.util.Random; import java.util.Scanner;public class Main {public static void rand(int[] a,int n){Random rnew Random();for (int i0;i<n;i){int rrr.nextInt(n);int tempa[i];a[i]a[rr];a[rr]temp;}}publ…

时间戳的转换-unix时间戳转换为utc时间(python实现)

import datetimetimestamp = 1711358882# 将时间戳转换为UTC时间 utc_time = datetime.datetime.utcfromtimestamp(timestamp)# 格式化并输出时间 formatted_time = utc_time.strftime(%Y-%m-%d %H:%M:%S) print(formatted_time)同样:UTC如何转换为unix时间戳 from datetime …

如何利用python 把一个表格某列数据和另外一个表格某列匹配 类似Excel VLOOKUP功能

环境: python3.8.10 Excel2016 Win10专业版 问题描述: 如何利用python 把一个表格某列数据和另外一个表格某列匹配 类似Excel VLOOKUP功能 先排除两表A列空白单元格,然后匹配x1表格和x2表格他们的A列,把x1表格中A列A1-A810范围对应的B列B1-B810数据,匹配填充到x2范围…

C语言程序与设计——预处理命令

宏 在C语言中宏有三种形式: 定义符号常量定义傻瓜表达式定义代码段 在使用宏的过程中需要注意的是&#xff0c;宏的作用仅仅是在预处理阶段对代码进行替换&#xff0c;而非进行运算&#xff0c;所以在使用时&#xff0c;如果出现了我们预期之外的结果&#xff0c;很有可能是宏…

Spring IoC DI(1)

IoC & DI入门 Spring 通过前面的学习, 我们知道了Spring是一个开源框架, 它让我们的开发更加简单. 它支持广泛的应用场景, 有着活跃且庞大的社区, 这就是Spring能够长久不衰的原因. 但是这个概念还是比较抽象. 可以用更具体的话描述Spring, 那就是: Spring是包含了众多…

Jakarta项目介绍

概述 在升级Spring Boot到3.0版本以后&#xff0c;或升级Spring到6.0版本以上&#xff0c;会发现应用编译失败或启动失败等问题。 经过排查不难得知&#xff0c;Spring 6或Spring Boot 3&#xff08;实际上依赖于Spring 6&#xff09;不再支持javax.开头的一系列依赖包&#…

人工智能的迷惑行为:AI世界的隐秘角落

人工智能迷惑行为大赏 在当今数字化时代&#xff0c;人工智能技术的飞速发展给我们的生活带来了诸多便利和可能性&#xff0c;但同时也伴随着一些令人困惑的现象和行为。本文将深入探讨人工智能的迷惑行为&#xff0c;揭示AI世界中的隐秘角落&#xff0c;让我们一同探寻这个充…

《深入浅出LLM 》(二):大模型基础知识

&#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系的学习资料&#xff0c;配有全面而有深度的专栏内容&#xff0c;包括不限于 前沿论文解读、…

CPU缓存行及伪共享

CPU Cache概述 随着CPU的频率不断提升&#xff0c;而内存的访问速度却没有质的突破&#xff0c;为了弥补访问内存的速度慢&#xff0c;充分发挥CPU的计算资源&#xff0c;提高CPU整体吞吐量&#xff0c;在CPU与内存之间引入了一级Cache。随着热点数据体积越来越大&#xff0c;…