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

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

作者: 小骄傲999 | 来源:发表于2023-07-12 10:40 被阅读0次

    因为博主使用的图文混排是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;
        }
    }
    

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/naxpudtx.html