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

2024-03-23 00:04

本文主要是介绍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;}
}

这篇关于TextMeshPro图文混排的两种实现方式,不打图集的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/836524

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Debezium 与 Apache Kafka 的集成方式步骤详解

《Debezium与ApacheKafka的集成方式步骤详解》本文详细介绍了如何将Debezium与ApacheKafka集成,包括集成概述、步骤、注意事项等,通过KafkaConnect,D... 目录一、集成概述二、集成步骤1. 准备 Kafka 环境2. 配置 Kafka Connect3. 安装 D

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景