[Unity]聊天界面中的图片长度处理

        最近又在改前人留下来的锅,聊天界面。在上线测试中,玩家普遍反映聊天界面卡,有反应那就需要解决。看了下,项目中用的是网上拉的一份代码,LinkImageText类。时间给的短,自己又懒得再去研究重写,费时间费力,所以自己测试了这个脚本,性能还是可以的,那就是调用的逻辑代码有问题了。

        仔细看了下代码,果然是逻辑有问题。首先先解释下聊天界面处理方式,界面没有隐藏是为了避免SetActive的消耗,只是把Scale全部缩放为0,这个可以理解。按理说,在没有打开聊天界面时,应该不进行任何计算,但是这边做法是有聊天信息直接用GameObject.Instante克隆并且修改Text文本,最可怕的是克隆会有350个,这不是在开玩笑吗。现在7个频道,每个历史记录50条,最多就会存在350条,而且还是挂载350个LinkImageText脚本,如果策划再增加频道和次数,不是直接炸了。界面上还有7个ScrollView,一时都不明白为啥要这样做。简单改了下,改成一个Text,只挂载一个LinkImageText脚本,去掉其余的ScrollView,剩下一个,不打开界面不进行任何计算。效果明显提升,从之前的降30帧,变为几乎不降帧(手机上),逻辑有问题后果还是蛮严重的。

        降帧问题一解决,策划马上提出新需求,需要语音的图片根据时间来变化长度。吐个槽,之前前面的人在的时候怎么不让前面的人做,如果一开始定好,就不用东改改西改改,挺烦的。

效果是是实现了,如图:

        LinkImageText脚本原作者的思路是对Text文本的顶点进行修改,那我就想了下,我在改本图片大小的时候,可以根据图片的大小,来对后面的文本的顶点位置进行偏移来实现效果。

        UIVertex vert = new UIVertex();
        for (var i = 0; i < m_ImagesVertexIndex.Count; i++)
        {
  
            var endIndex = m_ImagesVertexIndex[i];
            var rt = m_ImagesPool[i].rectTransform;
            var size = rt.sizeDelta;
            if (endIndex < toFill.currentVertCount)
            {
                toFill.PopulateUIVertex(ref vert, endIndex);
                rt.anchoredPosition = new Vector2(vert.position.x + size.x / 2, vert.position.y + size.y / 2-4);       
                // 抹掉左下角的小黑点
                toFill.PopulateUIVertex(ref vert, endIndex - 3);
                var pos = vert.position;
                for (int j = endIndex, m = endIndex - 3; j > m; j--)
                {
                    toFill.PopulateUIVertex(ref vert, endIndex);
                    vert.position = pos;
                    toFill.SetUIVertex(vert, j);
                }
                //根据图片大小偏移顶点位置
                var nextIndex = 0;
                if (m_ImagesVertexIndex.Count - i > 1)
                    nextIndex = m_ImagesVertexIndex[i + 1];
                else
                    nextIndex = toFill.currentVertCount;
                for (int textAfterImageIndex = endIndex + 1; textAfterImageIndex < nextIndex; ++textAfterImageIndex)
                {
                    toFill.PopulateUIVertex(ref vert, textAfterImageIndex);
                    //Debug.LogError("textAfterImageIndex: " + textAfterImageIndex + "--vert.position.x: " + vert.position.x + "--size.x: " + size.x);
                    vert.position.x += (size.x - 24) / 2;
                    toFill.SetUIVertex(vert, textAfterImageIndex);
                }

        发现效果不是很好,图片总是会遮挡住1,2个文本,达不到策划的需求。然后网上搜到原作者的博客,了解到了<quad name=xb_b size=25 width=1 />这个在UGUI中会变成占位符,而且width和height值会对占位符的长宽有影响。经测试,是按作者说的一样。我就想是不是这个width参数影响到了文本之前的距离,虽然我对文本的顶点进行了偏移,那我是否可以控制width来实现图片大小的变化。

        然后一堆改动,首先正则表达式修改:

    ///// <summary>
    ///// 正则取出所需要的属性
    ///// </summary>
    //private static readonly Regex s_ImageRegex =
    //    new Regex(@"<quad name=(.+?) size=(\d+?) width=(\d+?) />", RegexOptions.Singleline);
    private static readonly Regex s_ImageRegex =
        new Regex(@"<quad name=(.+?) size=(\d+?) width=([0-9]*\.?[0-9]*) />", RegexOptions.Singleline);

        语音图片大小修改

        m_VoiceImage.Clear();
        foreach (Match match in s_ImageRegex.Matches(m_OutputText))
        {
            var picIndex = match.Index;
            var endIndex = picIndex * 4 + 3;
            m_ImagesVertexIndex.Add(endIndex);

            m_ImagesPool.RemoveAll(image => image == null);
            if (m_ImagesPool.Count == 0)
            {
                GetComponentsInChildren<Image>(m_ImagesPool);
            }
            if (m_ImagesVertexIndex.Count > m_ImagesPool.Count)
            {
                var resources = new DefaultControls.Resources();
                var go = DefaultControls.CreateImage(resources);
                go.layer = gameObject.layer;
                var rt = go.transform as RectTransform;
                if (rt)
                {
                    rt.SetParent(rectTransform);
                    rt.localPosition = Vector3.zero;
                    rt.localRotation = Quaternion.identity;           
                    rt.localScale = Vector3.one;
                }
                m_ImagesPool.Add(go.GetComponent<Image>());
            }

            var spriteName = match.Groups[1].Value;
            var size = float.Parse(match.Groups[2].Value);
            var width = float.Parse(match.Groups[3].Value);
            var img = m_ImagesPool[m_ImagesVertexIndex.Count - 1];
            if (img.sprite == null || img.sprite.name != spriteName)
            {
                //加载图片
                img.type = Image.Type.Sliced;
                
            }
            //修改图片大小
            img.rectTransform.sizeDelta = new Vector2(size * width, size);
            if (spriteName == VoiceSDKInterface.VoiceSpriteName)//语音喇叭图片
            {
                img.raycastTarget = true;
                m_VoiceImage.Add(img);
                int index = m_VoiceImage.Count;
                EventTriggerAssist.SetTriggerEvent(img.gameObject, UnityEngine.EventSystems.EventTriggerType.PointerClick, (PointerEventData) => {
                    //Debug.LogError("c# index: " + index);
                    if (m_VoiceImage[index - 1] != img) return;
                    if (m_ImageLuaFunc != null)
                        m_ImageLuaFunc.Call(index);
                });
            }
            else
                img.raycastTarget = false;
            
            img.enabled = true;
        }

        最后把之前修改顶点位置的代码注释掉,嗯,效果实现达成策划的需求。有兴趣的还是去看下原作者的博客,写的很详细,挺不错的技术文章。

扫描二维码关注公众号,回复: 3546260 查看本文章

猜你喜欢

转载自blog.csdn.net/zp288105109a/article/details/82873086