Unity Text行首不显示标点符号(进阶版本)

因为博主使用的图文混排是InlineText,所以加了支持InlineText标点符号适配,你们在使用的时候可以把InlineText代码逻辑删了,或者换成你们的图文混排脚本,同时做了优化处理,比如同种道具点击时,显示的文字回来变,因此加了个Color细节优化,如果你们有更好的方案,也可以在评论区留言哦

using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.UI;
using Wanderer.EmojiText;

[RequireComponent(typeof(Text))]
public class LineFeedFixed : MonoBehaviour
{
    // Start is called before the first frame update
    private Text textCom;
    private InlineText inlineTextCom;
    private CanvasGroup canvasGroup;
    private string origStr;
    private string replaceStr;
    private string finalReplaceStr;

    /// 标记不换行的空格(换行空格Unicode编码为/u0020,不换行的/u00A0)
    public static readonly string Non_breaking_space = "\u00A0";
    /// 标记不换行
    public static readonly string[] _SpecialStructures = new string[6] { "<b>", "</b>", "<i>", "</i>", "</color>", "</size>"} ;

    /// 用于匹配标点符号,为了不破坏富文本标签,所以只匹配指定的符号
    private readonly string strPunctuation = @"[ , ; . ? ! | … : ,。;?、! ) ” ’ ) 》:— / \\ - \] 】} ]";

    /// 用于存储text组件中的内容
    private StringBuilder TempText = null;

    /// 用于存储text组件中的内容
    private StringBuilder InlineText = null;

    /// 用于存储text生成器中的内容
    private IList<UILineInfo> TextLine;

    private int screenWidth = 0;
    private int screenHeight = 0;
    //在替换后的文本最后面添加一个看不到的字符,以用于辨别当前输入的文本是不是原始文本
    private string endString = " ";

    private bool isReplacing = false;

    private string changeTextStr = string.Empty;
    private void OnEnable()
    {

        isReplacing = false;
        changeTextStr = string.Empty;
        CheckTextComponent();
        CheckScreenSizeChange();
        ReplaceTextFun();
    }
    // Update is called once per frame
    void Update()
    {
        if (CheckScreenSizeChange() == true)
        {
            if (textCom != null && string.IsNullOrEmpty(origStr) == false)
            {
                if (textCom != null)
                {
                    textCom.text = origStr;
                }
                replaceStr = "";
                finalReplaceStr = "";
            }
        }
        CheckReplaceText();
    }

    private bool CheckScreenSizeChange()
    {
        if (Screen.width != screenWidth || Screen.height != screenHeight)
        {
            screenWidth = Screen.width;
            screenHeight = Screen.height;
            return true;
        }
        else
        {
            return false;
        }
    }

    private void CheckTextComponent()
    {
        if (textCom != null)
        {
            return;
        }

        textCom = this.gameObject.GetComponent<Text>();
        inlineTextCom = textCom.GetComponent<InlineText>();
        canvasGroup = this.gameObject.GetComponent<CanvasGroup>();
        if (canvasGroup == null)
        {
            canvasGroup = this.gameObject.AddComponent<CanvasGroup>();
            canvasGroup.alpha = 0;
        }
    }

    private void CheckReplaceText()
    {
        if (textCom == null)
        {
            return;
        }
        if (CheckTextIsChange() == false)
        {
            return;
        }
        ReplaceTextFun();
    }

    private void ReplaceTextFun()
    {
        if (isReplacing == true)
        {
            return;
        }

        replaceStr = "";
        finalReplaceStr = "";
        StartCoroutine("ClearUpPunctuationMode");
    }

    private bool CheckTextIsChange()
    {
        if (textCom == null)
        {
            return false;
        }
        string txt = string.Empty;
        if (inlineTextCom)
        {
            txt = inlineTextCom.GetInputText();
        }
        else
        {
            txt = textCom.text;
        }
        if (string.Equals(txt, finalReplaceStr) == true)
        {
            return false;
        }
        return true;
    }

    IEnumerator ClearUpPunctuationMode()
    {
        isReplacing = true;
        canvasGroup.alpha = 0;
        yield return new WaitForSeconds(0.06f);
        //不能立刻就进行计算,要等起码渲染完上一帧才计算,所以延迟了60毫秒

        if (string.IsNullOrEmpty(textCom.text))
        {
            isReplacing = false;
        }
        else
        {
            string tempTxt = inlineTextCom != null ? inlineTextCom.GetInputText() : textCom.text;
            bool isOrigStr = false;
            if (tempTxt[tempTxt.Length - 1].ToString() != endString)
            {
                //如果结尾没有空白字符,就认为是原始的字符串,记录下来用于分辨率改变时再次计算
                origStr = tempTxt;
                isOrigStr = true;
            }
            TextLine = textCom.cachedTextGenerator.lines;
            //需要改变的字符序号
            int ChangeIndex = -1;

            if (inlineTextCom)
            {
                InlineText = new StringBuilder(inlineTextCom.GetInputText());
            }
            TempText = new StringBuilder(textCom.text);

            for (int i = 1; i < TextLine.Count; i++)
            {
                //首位是否有标点
                UILineInfo lineInfo = TextLine[i];
                int startCharIdx = lineInfo.startCharIdx;
                if (TempText.Length <= startCharIdx)
                {
                    continue;
                }
                string startCharStr = TempText[startCharIdx].ToString();
                bool IsPunctuation = Regex.IsMatch(startCharStr, strPunctuation);
                //因为将换行空格都改成不换行空格后需要另外判断下如果首字符是不换行空格那么还是需要调整换行字符的下标
                if (TempText[TextLine[i].startCharIdx].ToString() == Non_breaking_space)
                {
                    IsPunctuation = true;
                }

                //没有标点就跳过本次循环
                if (!IsPunctuation)
                {
                    continue;
                }
                else
                {
                    //有标点时保存当前下标
                    ChangeIndex = TextLine[i].startCharIdx;
                    //下面这个循环是为了判断当已经提前一个字符后当前这个的首字符还是标点时做的继续提前字符的处理
                    while (IsPunctuation)
                    {
                        ChangeIndex = ChangeIndex - 1;
                        if (ChangeIndex < 0) break;
                        //匹配下是否是富文本,是富文本特殊处理 </color> </size>
                        string changeIndexChar = TempText[ChangeIndex].ToString();
                        if (changeIndexChar.Equals(">"))
                        {
                            ChangeIndex = GetChangeIndex(ChangeIndex, changeIndexChar);
                            changeIndexChar = TempText[ChangeIndex].ToString();
                        }
                        if (changeIndexChar.Equals("<"))
                        {
                            if (ChangeIndex - 1 >= 0)
                            {
                                changeIndexChar = TempText[ChangeIndex - 1].ToString();
                                ChangeIndex = GetChangeIndex(ChangeIndex - 1, changeIndexChar);
                                changeIndexChar = TempText[ChangeIndex].ToString();
                            }
                        }

                        IsPunctuation = Regex.IsMatch(changeIndexChar, strPunctuation);
                        //因为将换行空格都改成不换行空格后需要另外判断下如果首字符是不换行空格那么还是需要调整换行字符的下标
                        if (TempText[ChangeIndex].ToString() == Non_breaking_space)
                        {
                            IsPunctuation = true;
                        }
                    }
                    if (ChangeIndex < 0) continue;

                    char tempTextChar = TempText[ChangeIndex];
                    if (tempTextChar != '\n')
                    {
                        if (inlineTextCom)
                        {
                            int charIndex = 0;      //被替换的char是第几个
                            for (int j = 0; j < TempText.Length; j++)
                            {
                                char compareTextChar = TempText[j];
                                if (compareTextChar.Equals(tempTextChar))
                                {
                                    charIndex++;
                                    if (j == ChangeIndex)
                                    {
                                        break;
                                    }
                                }
                            }
                            for (int j = 0; j < InlineText.Length; j++)
                            {
                                char tempInlineChar = InlineText[j];
                                if (tempInlineChar.Equals(tempTextChar))
                                {
                                    charIndex--;
                                    if (charIndex<=0)
                                    {
                                        ChangeIndex = j;
                                        break;
                                    }
                                }
                            }
                            InlineText.Insert(ChangeIndex, "\n");
                            //一次只能换一个,换后让text进行重新绘制,不然显示会有问题
                            break;
                        }
                        else
                        {
                            TempText.Insert(ChangeIndex, "\n");
                            //一次只能换一个,换后让text进行重新绘制,不然显示会有问题
                            break;
                        }
                    }
                }
            }

            if (inlineTextCom)
            {
                replaceStr = InlineText.ToString();
            }
            else
            {
                replaceStr = TempText.ToString();
            }

            if (string.Equals(tempTxt, replaceStr) == false)
            {
                //如果计算出来的最后结果和text组件当前的字符串不一致,证明有改动,改动后还需要继续判断
                //因为有可能在插入换行后,其他的地方会出现问题
                if (isOrigStr)
                {
                    replaceStr += endString;
                }
                textCom.text = replaceStr;
                
                changeTextStr = replaceStr;
                isReplacing = false;
            }
            else
            {
                //计算后的结果和当前text组件的字符串一致,证明当前text组件的字符串已经没有问题
                //记录下来,用于判断当前的字符串是否有改变
                finalReplaceStr = replaceStr;
                if (changeTextStr.Equals(replaceStr) || changeTextStr.Equals(string.Empty))
                {
                    canvasGroup.alpha = 1;
                    changeTextStr = string.Empty;
                    isReplacing = false;
                }
            }
        }
    }
    /// <summary>
    /// 递归判断改变索引
    /// </summary>
    /// <param name="changeIndex"></param>
    /// <param name="changeIndexChar"></param>
    ///<param 是否是大于号="isGt"></param>
    /// <returns></returns>
    private int GetChangeIndex(int changeIndex, string changeIndexChar)
    {
        if (!changeIndexChar.Equals(">"))
        {
            if (changeIndexChar.Equals("<"))
            {
                changeIndex = changeIndex - 1;
                if (changeIndex >= 0)
                {
                    changeIndexChar = TempText[changeIndex].ToString();
                    changeIndex = GetChangeIndex(changeIndex, changeIndexChar);
                }
            }
            return changeIndex;
        }
        bool existChange = false;
        //判断富文本字符列表
        for (int k = 0; k < _SpecialStructures.Length; k++)
        {
            string specialStructure = _SpecialStructures[k];
            string charSumStr = string.Empty;
            int startIndex = changeIndex - (specialStructure.Length - 1);
            if (startIndex >= 0)
            {
                for (int j = startIndex; j < changeIndex + 1; j++)
                {
                    charSumStr = charSumStr + TempText[j].ToString();
                }
                if (charSumStr.Equals(specialStructure))
                {
                    changeIndex = changeIndex - specialStructure.Length;
                    changeIndexChar = TempText[changeIndex].ToString();
                    changeIndex = GetChangeIndex(changeIndex, changeIndexChar);
                    existChange = true;
                    break;
                }
            }
        }
        //上边两个匹配一下,如果不是上边格式,匹配正则<color=#FFFFFF>or<size=24>
        if (!existChange)
        {
            string charSumStr = string.Empty;
            int startIndex = changeIndex - 15;
            if (startIndex >= 0)
            {
                for (int j = startIndex; j < changeIndex + 1; j++)
                {
                    charSumStr = charSumStr + TempText[j].ToString();
                }
                bool isHave = Regex.IsMatch(charSumStr, @"<color=#([0-9a-zA-Z]+)>");
                if (isHave)
                {
                    int tempChangeIndex = changeIndex - 16;
                    if (tempChangeIndex >= 0)
                    {
                        changeIndex = tempChangeIndex;
                        changeIndexChar = TempText[changeIndex].ToString();
                        changeIndex = GetChangeIndex(changeIndex, changeIndexChar);
                        existChange = true;
                    }
                }
            }

            if (!existChange)       //size仅支持两位数
            {
                startIndex = changeIndex - 9;
                if (startIndex >= 0)
                {
                    for (int j = startIndex; j < changeIndex + 1; j++)
                    {
                        charSumStr = charSumStr + TempText[j].ToString();
                    }
                    bool isHave = Regex.IsMatch(charSumStr, @"<size=([0-9]+)>");
                    if (isHave)
                    {
                        int tempChangeIndex = changeIndex - 10;
                        if (tempChangeIndex >= 0)
                        {
                            changeIndex = tempChangeIndex;
                            changeIndexChar = TempText[changeIndex].ToString();
                            changeIndex = GetChangeIndex(changeIndex, changeIndexChar);
                            existChange = true;
                        }
                    }
                }
            }
        }
        return changeIndex;
    }
    private void OnDisable()
    {
        if (!textCom) return;
        textCom.text = "";
        finalReplaceStr = "";
        canvasGroup.alpha = 0;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容