UGUI Text中文符号句首句尾问题

 经常在游戏开发中碰到中文符号在句首或句尾导致显示不正常的问题,而TextMeshPro就没有这些问题因为TMP支持配置,那对于项目中没法使用TMP的情况,而用的UGUI的Text的情况,怎么办呢?

比如下图:双引号单独在句尾了,这样显示特别不美观,而版署那边又要求修改。

 

解决后:

还有这种,句号在句首了,也很奇怪。

 百度谷歌也没找到合适的方案,或找到的方案有瑕疵,因此特地写了一个类,专门解决这种情况,支持配置避免行尾出现的符号、避免行首出现的符号等等,可直接拿去使用。

代码如下:

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

/// <summary>
/// 该类解决中文符号在句首或句尾的问题,符号在句尾会自动换行
/// </summary>
public class TextBreaking : MonoBehaviour
{
    public Text textToReformat;
    [Multiline]
    public string debugString;

    [Header("Debug")] 
    private readonly List<string> avoidLineEndingList = new List<string>() {"“"};//避免在行尾的符号
    private readonly List<string> avoidLineHeadList = new List<string>() {",", "!", "。"};//避免在行首的符号
    private readonly List<string> lineEndingList = new List<string>() {"\r\n", "\n", "\r"};//换行符列表
    [Multiline]
    private List<string> lineTextList = new List<string>();
    private string lineText;
    private int lineStartIndex;

    void Start()
    {
        Format();
    }

    [ContextMenu("Format")]
    void Format()
    {
        if (!string.IsNullOrEmpty(debugString))
        {
            textToReformat.text = debugString;
        }
        
        var generator = new TextGenerator();
        
        var settings = CopyFrom(textToReformat.GetGenerationSettings(textToReformat.rectTransform.rect.size));

        float boundWidth = textToReformat.rectTransform.sizeDelta.x;
        
        lineTextList.Clear();
        
        var value = textToReformat.text;
        //将\r\n替换为效果一样的\n,方便计算
        value = value.Replace("\r\n", "\n");
        
        var updatedText = "";
        int length = 0;
        lineText = "";
        lineStartIndex = 0;
        int lineLength = 0;
        while (length < value.Length)
        {
            length++;
            updatedText = value.Substring(0, length);
            //Debug.Log(updatedText + "==" + length); 
            
            lineLength++;
            if (lineStartIndex + lineLength > value.Length)
            {
                break;
            }
            lineText = value.Substring(lineStartIndex, lineLength); 

            float w = generator.GetPreferredWidth(lineText, settings) / settings.scaleFactor;
            
            var endValue = lineText.Substring(lineText.Length - 1, 1);
            //检测\r\n 这个上面将\r\n过滤掉了,可能不需要这样判断了
            var endValue2 = lineText.Length > 2 ? lineText.Substring(lineText.Length - 2, 2) : "";
            bool isLineEnding = lineEndingList.Contains(endValue2);
            if (!isLineEnding)
            {
                isLineEnding = lineEndingList.Contains(endValue);
            }

            if (isLineEnding)
            {
                length += 1;//判断是回车,长度需要增加1
                lineLength = 1;
                //lineText = value.Substring(lineStartIndex, 1);
                lineStartIndex = updatedText.Length;
                lineTextList.Add(lineText);
                continue;
            }
            if (w >= boundWidth)
            {
//                var endValue = lineText.Substring(lineText.Length - 1, 1);
                var endValue3=lineText.Length > 2 ? lineText.Substring(lineText.Length - 2, 1) : "";

                //判断句尾
                if (avoidLineEndingList.Contains(endValue3))
                {
                    int insertIndex = updatedText.Length - 2;
                    value = value.Insert(insertIndex, "\n");
                    lineText = value.Substring(lineStartIndex, insertIndex-lineStartIndex);
                    length -= 1;//插入后长度索引减掉
                    lineLength = 0;
                    lineStartIndex = insertIndex + 1;
                }
                //判断句首
                else if (avoidLineHeadList.Contains(endValue))
                {
                    int insertIndex = updatedText.Length - 2;
                    value = value.Insert(insertIndex, "\n");
                    lineText = value.Substring(lineStartIndex, insertIndex-lineStartIndex);
                    length -= 1;//插入后长度索引减掉
                    lineLength = 0;
                    lineStartIndex = insertIndex + 1;
                }
                else
                {
                    lineLength = 1;
                    lineText = value.Substring(lineStartIndex, lineText.Length - 1);
                    lineStartIndex = updatedText.Length-1;
                }
                lineTextList.Add(lineText);

                //Debug.Log("[AA]"+lineText + "==" + w + "===" + length);
            }
        }
 
        textToReformat.text = updatedText;
    }
    
    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
        };
    }
}

如何配置符号,看下图

实现原理

对于实现的原理,其实很暴力,就是遍历每一行,一个字一个字测试是否超过,判断其是否在行尾或行首,手动增加换行符让显示正常。

https://github.com/cooloo/TextBreakingicon-default.png?t=M4ADhttps://github.com/cooloo/TextBreaking

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鱼蛋-Felix

如果对你有用,可以请我喝杯可乐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值