【Unity】Text组件标点符号句首优化(Text标点符号开头、标点符号换行)

这篇具有很好参考价值的文章主要介绍了【Unity】Text组件标点符号句首优化(Text标点符号开头、标点符号换行)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

今天碰到一个需求,项目中有时候的Text的文本会出现标点符号在句首的情况。
unity text自适应标点符号不在头尾,Unity,unity,c#,linq,游戏引擎,ui
需求是标点符号不能出现在句首,而且我们项目是自适应的,不同分辨率下Text的宽不同,这就导致了无论怎样修改文案,都可能会出现标点符号在句首的情况,所以要改进一下。
在网上搜到了一些解决方案的代码,放到项目里发现有问题没办法用,而且比较复杂有点难理解,所以我就研究了一下,写了一个比较简单的解决方案。

原理

暴力排序
首先我们要把字符串分割来看。
unity text自适应标点符号不在头尾,Unity,unity,c#,linq,游戏引擎,ui
那么通常情况下,Text应该是这样排列的
unity text自适应标点符号不在头尾,Unity,unity,c#,linq,游戏引擎,ui

相当于先获取到Text文本框的宽度,再获取到当前文本所占的宽(不同汉字的像素宽是不同的,所以没办法准确的获取一个汉字的宽)。
再进行判断,当放到某个字时文本的宽度超出了文本框的宽度,那么就说明这个字是要换行的。
再判断这个字是不是标点符号,是的话就把它和它前面的一个字拿到另一行。
就像这样
unity text自适应标点符号不在头尾,Unity,unity,c#,linq,游戏引擎,ui
那么这样就简单地实现了句首标点符号的处理方法

注意

没有加空格的判断,所以要确保文本中不能出现空格;
文本框必须能获取到宽度;
如果使用自动布局组件的话,偶尔情况下可能当前帧的文本框宽度为0,需要延迟处理

但是这个代码现在还有个缺陷,那就是经过处理的文本有时候会长短不一,看起来有点丑
unity text自适应标点符号不在头尾,Unity,unity,c#,linq,游戏引擎,ui
但是大部分情况下应该够用了

使用方法

通过Text组件调用
unity text自适应标点符号不在头尾,Unity,unity,c#,linq,游戏引擎,ui
不知道我的方法性能开销大不大,本人是Unity新手,如果有改进的地方欢迎提出来!!
其实应该还有另外的解决方案,比如TextMeshPro,感兴趣的小伙伴可以研究一下。

代码


using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// 字符串标点符号格式化
/// </summary>
public static class StringPunctuationFormatting
{
    static List<string> punctuations = new List<string> {
        ",",    ",",
        "!",    "!",
        "。",    ".",
        "?",    "?",
        "~",
        "+",    "-",    "*",    "/",
        "《",    "<",
        "》",    ">",
        "、",    @"\",
        ":",    ":",
        ";",    ";",
        "“",    "\'",
        "”",    "‘",    "’",

    };

    static int MinFontSize = 30;
    static int MaxFontSize = 40;

    static IEnumerator FrameEnumerator(Text TextComponent)
    {
        yield return new WaitUntil(() => Alignment(TextComponent.transform) != 0);
        PunctuationFormat(TextComponent);

        //while (true)
        //{
        //    float result = Alignment(TextComponent.transform);
        //    if (result != 0)
        //    {
        //        PunctuationFormat(TextComponent);
        //        yield break;
        //    }
        //    yield return null;
        //}

    }

	///在对象或者父对象有自动布局组件的时候,会出现文本框宽度在下一帧才有具体值,因此要进行延迟处理
    /// <summary>
    /// 延迟执行标点符号处理
    /// </summary>
    public static void LateFramePunctuationFormat(this Text TextComponent)
    {
        TextComponent.StartCoroutine(FrameEnumerator(TextComponent));       
    }


    /// <summary>
    /// 标点符号格式化
    /// </summary>
    /// <param name="TextComponent">文本组件</param>
    public static void PunctuationFormat(this Text TextComponent)
    {
        //Debug.LogError("执行处理");  
        string text = TextComponent.text;

        if (text == string.Empty || text == "" || text.Length == 0)
        {
            Debug.LogError("字符串为空");
            return;
        }
		
        //获取文本框宽度
        float boundWidth = Alignment(TextComponent.transform);
        
        //如果Text组件使用bestfit,那么会根据文本框宽度计算字体大小,通常情况下SetTextFontSize方法需要根据项目需求改写
		if (TextComponent.resizeTextForBestFit)
		    TextComponent.fontSize = SetTextFontSize(text.Length, (int)boundWidth);

        

        TextGenerator generator = new TextGenerator();
        TextGenerationSettings settings = CopyFrom(TextComponent.GetGenerationSettings(TextComponent.rectTransform.rect.size));//获取文本框数据
        

        

        List<string> charList = StringFormat(text);
        List<string> stringList = new List<string>();
        string str = string.Empty;
        float width;
        foreach (var item in charList)
        {
            str += item;//当前组合的字符
            TextComponent.text = str;
            width = generator.GetPreferredWidth(TextComponent.text, settings) / settings.scaleFactor;//当前文本宽度
            if (width > boundWidth)//说明这次添加的字导致了换行
            {
                string line;//处理好的一行字
                if (isPunctuation(item))//判断是否为标点
                {
                    line = str.Substring(0, str.Length - 2);//将最后一个字拿给下一行
                    str = str.Substring(str.Length - 2, 2);
                }
                else
                {
                    line = str.Substring(0, str.Length - 1);
                    str = str.Substring(str.Length - 1, 1);
                }
                //再次判断最后一个字是否为标点
                lastOneIsPun(ref line, ref str);
                stringList.Add(line);
            }

            //如果是最后一次循环且没超行,
            //为了避免有和结尾一样的字时误以为结束,要判断内存地址是否相同
            if (object.ReferenceEquals(item, charList.LastOrDefault()))
            {
                stringList.Add(str);
            }
        }
        
        //以下处理单字不成行
        if (stringList.Count > 1 && stringList[stringList.Count - 1].Length <= 3) //判断最后一行字数,如果是单字的话
        {
            Debug.LogError("单子不成行");
            string newLine= stringList[stringList.Count - 2].Substring(0, stringList[stringList.Count - 2].Length - 1);
            string x= stringList[stringList.Count - 2].Substring(stringList[stringList.Count - 2].Length - 1, 1);//上一行的最后一个字
            stringList[stringList.Count - 2] = newLine;//删去一个字的新行
            stringList[stringList.Count - 1]=stringList[stringList.Count - 1].Insert(1, x);//添加给新一行
        }
        
        string endstring = string.Empty;
        for (int i = 0; i < stringList.Count; i++)
        {
            endstring += stringList[i];            

        }
        //foreach (var item in stringList)
        //{
        //    Debug.LogError(item);
        //    endstring += item;
        //}
        TextComponent.text = endstring;
    }
    /// <summary>
    /// 判断最后一个字是否为标点
    /// </summary>
    /// <returns></returns>
    static void lastOneIsPun(ref string line, ref string str)
    {
        if (isPunctuation(str[0].ToString()))//如果第一个字是标点
        {
            str = line.Substring(line.Length - 1, 1) + str;
            line = line.Substring(0, line.Length - 1);
            lastOneIsPun(ref line, ref str);
            return;
        }
        str = "\n" + str;
    }
    static bool isPunctuation(string item)
    {
        foreach (var pun in punctuations)
        {
            if (item == pun)
                return true;
        }
        return false;
    }

    /// <summary>
    /// 获取文本框的宽
    /// </summary>
    /// <param name="transform"></param>
    /// <returns>文本框宽度</returns>
    static float Alignment(Transform transform)
    {
        RectTransform rectTransform = transform.GetComponent<RectTransform>();
        return rectTransform.rect.width;
    }

    /// <summary>
    /// 格式化字符串
    /// </summary>
    /// <param name="str"></param>
    /// <returns>每个字符的列表</returns>
    static List<string> StringFormat(string str)
    {
        List<string> strlist = new List<string>();
        for (int i = 0; i < str.Length; i++)
        {
            strlist.Add(str.Substring(0, 1));
            str = str.Substring(1);
            i--;
        }
        return strlist;
    }


    /// <summary>
    /// 设置字体大小,最小为30最大为40。以文本框宽400,字体40为标准来计算:每多2个字字号减小1,文本框宽度每增加80,每多两个字的基础上再多一个字字号才减1
    /// </summary>
    /// <param name="length"></param>
    /// <returns></returns>
    static int SetTextFontSize(int length,int width)
    {
        int force = Mathf.Max(0, (width - 400) / 80);
        int newSize = MaxFontSize - (length - MaxFontSize) / (force+2);
        return Mathf.Clamp(newSize, MinFontSize, MaxFontSize);
    }


    /// <summary>
    /// 获取Text组件配置属性
    /// </summary>
    /// <param name="o"></param>
    /// <returns></returns>
    static TextGenerationSettings CopyFrom(TextGenerationSettings o)
    {
        return new TextGenerationSettings
        {
            font = o.font,
            color = o.color,
            fontSize = o.fontSize,
            lineSpacing = o.lineSpacing,
            richText = o.richText,
            scaleFactor = o.scaleFactor,
            fontStyle = o.fontStyle,
            textAnchor = o.textAnchor,
            alignByGeometry = o.alignByGeometry,
            resizeTextForBestFit = o.resizeTextForBestFit,
            resizeTextMinSize = o.resizeTextMinSize,
            resizeTextMaxSize = o.resizeTextMaxSize,
            updateBounds = o.updateBounds,
            verticalOverflow = o.verticalOverflow,
            horizontalOverflow = o.horizontalOverflow,
            generationExtents = o.generationExtents,
            pivot = o.pivot,
            generateOutOfBounds = o.generateOutOfBounds
        };
    }

}



示例//未更新

示例Demo

参考文献

参考文献文章来源地址https://www.toymoban.com/news/detail-780202.html

到了这里,关于【Unity】Text组件标点符号句首优化(Text标点符号开头、标点符号换行)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python使用jieba库分词并去除标点符号

    相对于英文文本,中文文本挖掘面临的首要问题就是分词,因为中文的词之间没有空格。在Python中可以使用jieba库来进行中文分词。 但是在中文中,标点符号出现的频率也是很高的,在使用jieba库对带有标点符号的汉语句子进行分词时,标点符号出现在分词结果中时,对于后

    2024年02月04日
    浏览(75)
  • word@通配符@高级搜索查找@替换@中英文标点符号替换

    Find text - Microsoft Support 通配符 在搜索中使用通配符 - Microsoft 支持 Examples of wildcard characters - Microsoft Support Power User Tips and Tricks - Word, Excel, Dreamweaver (ntu.edu.sg) Using wildcards - Microsoft Word 365 (officetooltips.com) 批量选中引用序号@上标调整 利用上述方法,可以一次性将正文中的citations

    2024年02月10日
    浏览(49)
  • 从0开始学Java:运算符(Operator)与标点符号(Separators)

    运算符: 是一种特殊的符号,用以表示数据的运算、赋值和比较等。 表达式: 用运算符连接起来的式子 在Java中,一共有38个运算符。 按照功能划分: 分类 运算符 算术运算符 + 、 - 、 * 、 / 、 % 、 ++ 、 -- 赋值运算符 = 、 += 、 -= 、 *= 、 /= 、 %= 等 关系运算符 、 = 、 、

    2024年02月08日
    浏览(49)
  • 用html+javascript打造公文一键排版系统14:为半角和全角字符相互转换功能增加英文字母、阿拉伯数字、标点符号、空格选项

    在昨天我们实现了最简单的半角字符和全角字符相互转换功能,就是将英文字母、阿拉伯数字、标点符号、空格全部进行转换。 在实际工作中,我们有时只想英文字母、阿拉伯数字、标点符号、空格之中的一两类进行转换,而其它的保持不变。 比如将半角英文字母转换为全

    2024年02月14日
    浏览(38)
  • Unity的UGUI避免行的开头出现符号

    大家好,我是阿赵。最近在游戏过版署的时候,修改意见里面有一条,游戏内部分文本内容中有标点符号出现在行首的问题。 一般来说,我们编辑文本的时候,是会注意不要把标点符号在换行的时候刚好出现的在行首的,但这个问题,似乎不是策划编辑文本时的问题。这里我

    2024年02月05日
    浏览(41)
  • 【Unity】Text文本组件的一些操作

    Text组件是Unity中用于在UI界面上显示文本的组件。它包含了一些常见的属性和方法,可以用来控制文本的内容、外观和交互。以下是一些常见的Text组件的操作: 设置文本内容:通过直接在Unity编辑器中的Text组件上输入文本,或者在代码中使用 text 属性来设置文本内容。 设置

    2024年02月11日
    浏览(43)
  • Unity的Text组件里面如何实现首行缩进

    一般而言,MyText.text里面要输入首行空格,那是不可能的。 譬如输入如下的内容: 那用什么方法呢?当然是用【全角空格\\\"u3000\\\"】。 在这个代码中,u3000 表示全角空格,通过 content += “u3000” + “u3000” + str + “n”; 这一行代码,实现了在当前段落的每行文本前添加两个全

    2024年02月04日
    浏览(40)
  • Unity UGUI的Text(文本)组件的介绍及使用

    UGUI(Unity Graphic User Interface)是Unity引擎的一套用户界面系统,而Text(文本)组件是UGUI中用于在游戏界面中显示文本的组件。该组件可以用于显示游戏中的文字、数字、标签等信息。 使用UGUI的Text组件可以在游戏界面中实时显示文字信息,方便玩家了解游戏的状态、交互信息

    2024年02月12日
    浏览(67)
  • 【Unity-UGUI控件全面解析】| Text文本组件详解

    🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN 🙉 🎄 学习专栏推荐:Unity系统学习专栏 🌲 游戏制作专栏推荐:游戏制作 🌲Unity实战100例专栏推荐:Unity 实战100例 教程 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📆 未来很长

    2024年02月04日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包