系统通知弹窗(CanvasGroup组件实现淡入淡出)

发不了短视频只好贴张图了测试

主要是在实现淡入淡出时用到了Canvas Group组件:
spa

组件比较简单,有四个属性:3d

Alpha:透明度
Interactable:是否禁用输入交互
Block Raycasts:是否禁用射线检测
Ignore Parent Groups:是否忽略父级Canvas Groupcode

该组件做用于挂载该组件的GameObject及其子物体。利用这一点,能够控制整个UI窗口的Alpha值,而没必要纠结其下有多少子物体,也能够利用该组件设置整个窗口内全部组件的不可点击。orm


由于通知内容长度不定,窗口大小和文本框要自动缩放:视频

PopupMessageCenter做为父节点,挂载控制脚本"PopupMessageCenter"(代码附在文末),全部的弹窗GameObject都将挂到该父节点下。Vertical Layout Group组件会缩放子物体的宽度与父节点同宽,Content Size Fitter组件会根据子物体的数量及大小缩放父物体大小。blog

Popup Prefab是弹窗窗体,也是预设体,Vertical Layout Group组件能够根据子物体大小缩放窗体大小,Canvas Group组件实现淡入淡出,并禁用输入交互。get

InfoText用来显示消息内容,Text组件的Vertical Overrflow属性,文字排版纵向溢出,Content Size Fitter组件会根据文字内容多少自动调整文本框大小。string

代码部分,都加了注释说明,比较简单就很少说了:it

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

namespace SimpleFrame
{
    //弹窗消息类
    class MessageInfo
    {
        public string infoStr { get; private set; }
        public Color color { get; private set; }

        public MessageInfo(string messageStr, Color messageColor)
        {
            infoStr = messageStr;
            color = messageColor;
        }
    }

    public class PopupMessageCenter : MonoBehaviour
    {
        //淡入/淡出时间
        [SerializeField] float fadeTime = 0.5f;
        //持续显示时间
        [SerializeField] float showTime = 3f;
        //最多显示数量
        [SerializeField] int maxShowCount = 5;

        //消息弹窗预设
        Transform popupPrefab;
        //当前显示数量
        int curShowCount;
        //待显示消息列表
        Stack<MessageInfo> infoStack = new Stack<MessageInfo>();
        //全部可用弹窗列表
        Stack<Transform> popupStack = new Stack<Transform>();

        void Awake()
        {
            Init();
        }

        void Update()
        {
            //测试代码
            if(Input.GetKeyDown(KeyCode.Alpha1))
            {
                AddMessageInfo("哈哈哈哈哈哈哈哈哈哈哈", Color.red);
            }
            else if(Input.GetKeyDown(KeyCode.Alpha2))
            {
                AddMessageInfo("嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿", Color.grey);
            }
            else if (Input.GetKeyDown(KeyCode.Alpha3))
            {
                AddMessageInfo("嘻嘻嘻嘻嘻嘻嘻嘻", Color.green);
            }
        }

        public void Init()
        {
            //初始化消息弹窗设置
            popupPrefab = transform.Find("PopupPrefab");

            CanvasGroup prefabGroup = popupPrefab.GetComponent<CanvasGroup>();
            if (prefabGroup == null)
                prefabGroup = popupPrefab.gameObject.AddComponent<CanvasGroup>();
            prefabGroup.alpha = 0;
            prefabGroup.interactable = false;
            prefabGroup.blocksRaycasts = false;

            popupPrefab.gameObject.SetActive(false);
        }

        //添加消息
        public void AddMessageInfo(string infoStr, Color infoColor)
        {
            //当前显示数量是否达到上限
            if (curShowCount < maxShowCount)
            {
                //显示
                ShowMessageInfo(infoStr, infoColor);
            }
            else
            {
                //添加到待显示列表
                infoStack.Push(new MessageInfo(infoStr, infoColor));
            }
        }

        //展现消息
        void ShowMessageInfo(string infoStr, Color infoColor)
        {
            if (curShowCount >= maxShowCount)
                return;

            curShowCount++;

            Transform tmpInfoObj;
            if (popupStack.Count > 0)
                tmpInfoObj = popupStack.Pop();
            else
                tmpInfoObj = Instantiate(popupPrefab, transform);

            //设置子物体顺序, 即最新显示的弹窗在最上面
            tmpInfoObj.SetSiblingIndex(0);

            //设置显示内容
            Text tmpText = tmpInfoObj.GetComponentInChildren<Text>();
            tmpText.text = infoStr;
            tmpText.color = infoColor;

            StartCoroutine(ShowMessagePopup(tmpInfoObj.gameObject));
        }

        IEnumerator ShowMessagePopup(GameObject infoObj)
        {
            CanvasGroup tmpGroup = infoObj.GetComponent<CanvasGroup>();
            tmpGroup.alpha = 0;
            //开始显示
            infoObj.gameObject.SetActive(true);
            tmpGroup.DOFade(1, fadeTime);

            //持续一段时间
            yield return new WaitForSeconds(fadeTime + showTime);

            //开始隐藏
            tmpGroup.DOFade(0, fadeTime);
            yield return new WaitForSeconds(fadeTime);
            infoObj.gameObject.SetActive(false);
            popupStack.Push(infoObj.transform);

            curShowCount--;

            //若是待显示列表不为空, 继续显示
            if (infoStack.Count > 0)
            {
                MessageInfo tmpInfo = infoStack.Pop();
                if (tmpInfo != null)
                {
                    ShowMessageInfo(tmpInfo.infoStr, tmpInfo.color);
                }
            }
        }
    }
}