引用:https://zhuanlan.zhihu.com/p/85978429
红点系统总览
如上图所示,规划红点系统的时候,我们将整个系统分为独立的三个部分:结构层、驱动层和表现层。
结构层用来部署红点的层级结构,做过红点系统的都知道,很多时候红点系统的层级都很深,所以我们要用一个结构来描述层级,这个就是我们今天的主题,树结构。
驱动层是指,如何驱动这个树结构产生状态变化,以及状态变化之后如何将变化的行为通知到指定的表现层,在一定的程度上将数据和表现分离开。
表现层就专门承担表现的职责,比如有的红点就是一个单纯的红点,有的需要显示数字,有的可能是图标晃动,有的是显示new标签,有的是播放特效等等。这些都可以归属在表现层统一去管控。
demo 设计
在这样一个界面先,我们可以看到主界面有三个主要入口,分别是 公会、任务、邮件。邮件界面里,又分为三个标签,系统、队伍、公会。
代码设```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RedPointConst
{
public const string main = "Main";
public const string mail = "Main.mail";
public const string mailTeam = "Main.mail.mailTeam";
public const string mailSystem = "Main.mail.System";
}
定一个Const类,按照系统来划分树的各个节点,比如上面展示的红点树结构,代码可以使用string来完成。这个定义不仅仅是用来规划结构,也会为后面事件驱动的时候提供key。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RedPointNode
{
public string nodeName;
public int pointNum = 0;
public RedPointNode parent = null;
public RedPointSystem.OnPointNumChange OnPointNumChange;
public Dictionary<string, RedPointNode> dicChilds = new Dictionary<string, RedPointNode>();
public void SetRedPointNum(int rpNum)
{
if (dicChilds.Count > 0)
{
Debug.LogWarning("onlyC案setleaf Node");
return;
}
pointNum = rpNum;
NotifyPointNumChange();
if (parent != null)
{
parent.ChangePredPointNum();
}
}
public void ChangePredPointNum()
{
int num = 0;
foreach (var item in dicChilds.Values)
{
num += item.pointNum;
}
if (num != pointNum)
{
pointNum = num;
if (parent != null)
parent.ChangePredPointNum();
NotifyPointNumChange();
}
}
public void NotifyPointNumChange()
{
OnPointNumChange?.Invoke(this);
}
}
红点的属性以及所需要的回调函数。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RedPointSystem
{
public delegate void OnPointNumChange(RedPointNode node);
RedPointNode mRootNode;
static List<string> istRedPointTreeList = new List<string>
{
RedPointConst.main,
RedPointConst.mail,
RedPointConst.mailTeam,
RedPointConst.mailSystem,
};
public void InitRedPointTreeNode()
{
mRootNode = new RedPointNode();
mRootNode.nodeName = RedPointConst.main;
foreach (var s in istRedPointTreeList)
{
var node = mRootNode;
var treeNodeAy = s.Split('.');
if (treeNodeAy.Length > 1)
{
for (int i = 0; i < treeNodeAy.Length; i++)
{
if (!node.dicChilds.ContainsKey(treeNodeAy[i]))
node.dicChilds.Add(treeNodeAy[i], new RedPointNode());
node.dicChilds[treeNodeAy[i]].nodeName = treeNodeAy[i];
node.dicChilds[treeNodeAy[i]].parent = node;
node = node.dicChilds[treeNodeAy[i]];
}
}
}
}
public void SetRedPointNodeCallBack(string strNode, RedPointSystem.OnPointNumChange callBack)
{
var nodeList = strNode.Split('.');
var node = mRootNode;
for (int i = 0; i < nodeList.Length; i++)
{
if (!node.dicChilds.ContainsKey(nodeList[i]))
{
Debug.LogWarning("未找到父节点" + nodeList[i]);
return;
}
node = node.dicChilds[nodeList[i]];
if (i == nodeList.Length - 1)
{
node.OnPointNumChange = callBack;
}
}
}
public void SetInvoke(string strNode, int rpNum)
{
var nodeList = strNode.Split('.');
var node = mRootNode;
for (int i = 0; i < nodeList.Length; i++)
{
if (!node.dicChilds.ContainsKey(nodeList[i]))
{
Debug.LogWarning("未找到父节点" + nodeList[i]);
return;
}
node = node.dicChilds[nodeList[i]];
if (i == nodeList.Length - 1)
{
node.SetRedPointNum(rpNum);
}
}
}
}
红点管理器,注册了所有的const红点。
demo 展示 红点的驱动层和回调展示层
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BootStart : MonoBehaviour
{
public Image imgMail;
public Image imgMailSystem;
public Image imgMailTeam;
public Text textMail;
public Text textMailSystem;
public Text textMailTeam;
private void Start()
{
RedPointSystem rps = new RedPointSystem();
rps.InitRedPointTreeNode();
rps.SetRedPointNodeCallBack(RedPointConst.mail,MailCallBack);
rps.SetRedPointNodeCallBack(RedPointConst.mailSystem, MailSystemCallBack);
rps.SetRedPointNodeCallBack(RedPointConst.mailTeam, MailTeamCallBack);
rps.SetInvoke(RedPointConst.mailSystem,3);
rps.SetInvoke(RedPointConst.mailTeam,2);
void MailCallBack(RedPointNode node)
{
textMail.text = node.pointNum.ToString();
imgMail.gameObject.SetActive(node.pointNum>0);
}
void MailSystemCallBack(RedPointNode node)
{
textMailSystem.text = node.pointNum.ToString();
imgMailSystem.gameObject.SetActive(node.pointNum > 0);
}
void MailTeamCallBack(RedPointNode node)
{
textMailTeam.text = node.pointNum.ToString();
imgMailTeam.gameObject.SetActive(node.pointNum > 0);
}
}
}