汉中市网站建设_网站建设公司_测试上线_seo优化
2026/1/6 19:25:37 网站建设 项目流程

红点模块主要通过树结构完成,先使用一个普通的树结构实现

主要特性

  1. 树形结构管理:支持父子节点的层级关系

  2. 自动传播:子节点变化自动更新父节点状态

  3. 事件通知:红点变化时触发事件,便于UI更新

  4. 多种操作:设置、增加、减少、清空红点数量

  5. 灵活查询:检查节点状态,获取红点数量

using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; /// <summary> /// 红点节点 /// </summary> public class RedDotNode { // 节点Key public string Key { get; private set; } // 节点显示名称(可选) public string Name { get; private set; } // 红点数量 public int Count { get; private set; } // 是否显示红点(Count > 0) public bool IsActive => Count > 0; // 父节点 public RedDotNode Parent { get; private set; } // 子节点 private Dictionary<string, RedDotNode> _children = new Dictionary<string, RedDotNode>(); public IReadOnlyDictionary<string, RedDotNode> Children => _children; // 红点变化事件 public event Action<RedDotNode> OnValueChanged; public RedDotNode(string key, string name = null) { Key = key; Name = name ?? key; } /// <summary> /// 设置红点数量 /// </summary> public void SetCount(int count) { if (Count == count) return; Count = Math.Max(0, count); OnValueChanged?.Invoke(this); // 通知父节点重新计算 Parent?.UpdateFromChildren(); } /// <summary> /// 增加红点数量 /// </summary> public void AddCount(int delta = 1) { SetCount(Count + delta); } /// <summary> /// 减少红点数量 /// </summary> public void ReduceCount(int delta = 1) { SetCount(Math.Max(0, Count - delta)); } /// <summary> /// 清空红点 /// </summary> public void Clear() { SetCount(0); } /// <summary> /// 添加子节点 /// </summary> public void AddChild(RedDotNode child) { if (child == null || child == this) return; child.Parent?.RemoveChild(child.Key); child.Parent = this; _children[child.Key] = child; // 监听子节点变化 child.OnValueChanged += OnChildValueChanged; // 更新当前节点状态 UpdateFromChildren(); } /// <summary> /// 移除子节点 /// </summary> public bool RemoveChild(string key) { if (_children.TryGetValue(key, out var child)) { child.OnValueChanged -= OnChildValueChanged; child.Parent = null; _children.Remove(key); UpdateFromChildren(); return true; } return false; } /// <summary> /// 获取子节点 /// </summary> public RedDotNode GetChild(string key) { return _children.TryGetValue(key, out var child) ? child : null; } /// <summary> /// 根据子节点更新当前节点状态 /// </summary> public void UpdateFromChildren() { if (_children.Count == 0) return; // 计算策略:只要有任意子节点有红点,父节点就显示红点 //int newCount = _children.Values.Any(child => child.IsActive) ? 1 : 0; // 或者计算所有子节点红点总和 int newCount = _children.Values.Sum(child => child.Count); if (Count != newCount) { Count = newCount; OnValueChanged?.Invoke(this); Parent?.UpdateFromChildren(); } } /// <summary> /// 子节点值变化回调 /// </summary> private void OnChildValueChanged(RedDotNode child) { UpdateFromChildren(); } /// <summary> /// 获取节点路径 /// </summary> public string GetPath() { var path = new List<string>(); var node = this; while (node != null) { path.Insert(0, node.Key); node = node.Parent; } return string.Join(".", path); } /// <summary> /// 打印节点树结构 /// </summary> public void PrintTree(string indent = "", bool last = true) { Debug.Log(indent); if (last) { Debug.Log("└─ "); indent += " "; } else { Debug.Log("├─ "); indent += "│ "; } Debug.Log($"{Name}{(IsActive ? $" [红点:{Count}]" : "")}"); var childrenList = _children.Values.ToList(); for (int i = 0; i < childrenList.Count; i++) { childrenList[i].PrintTree(indent, i == childrenList.Count - 1); } } } public class RedDotSystem { public static RedDotSystem Instance { get; } = new RedDotSystem(); // 根节点 private RedDotNode _root; // 所有节点字典 private Dictionary<string, RedDotNode> _allNodes = new Dictionary<string, RedDotNode>(); public RedDotNode Root => _root; private RedDotSystem(string rootKey = "Root", string rootName = "根节点") { _root = new RedDotNode(rootKey, rootName); _allNodes[rootKey] = _root; } /// <summary> /// 注册节点 /// </summary> public RedDotNode RegisterNode(string key, string name = null, string parentKey = null) { if (_allNodes.ContainsKey(key)) { return _allNodes[key]; } var node = new RedDotNode(key, name ?? key); _allNodes[key] = node; // 连接到父节点 if (!string.IsNullOrEmpty(parentKey)) { if (_allNodes.TryGetValue(parentKey, out var parent)) { parent.AddChild(node); } else { Debug.Log("Parent Null"); // 如果父节点不存在,先挂到根节点,等父节点创建后再调整 _root.AddChild(node); } } else { // 没有指定父节点,挂到根节点 _root.AddChild(node); } return node; } /// <summary> /// 获取节点 /// </summary> public RedDotNode GetNode(string key) { return _allNodes.TryGetValue(key, out var node) ? node : null; } /// <summary> /// 设置节点红点数量 /// </summary> public void SetNodeCount(string key, int count) { if (_allNodes.TryGetValue(key, out var node)) { node.SetCount(count); } } /// <summary> /// 增加节点红点数量 /// </summary> public void AddNodeCount(string key, int delta = 1) { if (_allNodes.TryGetValue(key, out var node)) { node.AddCount(delta); } } /// <summary> /// 清空节点红点 /// </summary> public void ClearNode(string key) { if (_allNodes.TryGetValue(key, out var node)) { node.Clear(); } } /// <summary> /// 清空所有红点 /// </summary> public void ClearAll() { foreach (var node in _allNodes.Values) { node.Clear(); } } /// <summary> /// 检查节点是否有红点 /// </summary> public bool CheckNodeActive(string key) { return _allNodes.TryGetValue(key, out var node) && node.IsActive; } /// <summary> /// 打印整棵树 /// </summary> public void PrintTree() { Debug.Log("=== 红点树结构 ==="); _root.PrintTree(); Debug.Log("================="); } }

测试代码:

public class GameStart : MonoBehaviour { // Start is called before the first frame update void Start() { RedDotSystem.Instance.RegisterNode("A", "A"); RedDotSystem.Instance.RegisterNode("B", "B", "A"); RedDotSystem.Instance.RegisterNode("C", "C", "A"); } }
public class RedNodeCom : MonoBehaviour { public string nodeKey; public string parentKey; RedDotNode RedDot; public TMPro.TextMeshProUGUI redText; public Button button; void Start() { if (string.IsNullOrEmpty(nodeKey)) { return; } RedDot = RedDotSystem.Instance.RegisterNode(nodeKey, nodeKey, parentKey); RedDot.OnValueChanged += RedDot_OnValueChanged; button.onClick.AddListener(() => { RedDot.AddCount(1); }); } private void RedDot_OnValueChanged(RedDotNode node) { Debug.Log($"RedDot Node {node.Key} changed to {node.Count}"); redText.text = node.Key + " - "+ node.Count.ToString(); } }

测试场景中,将下方BC按钮关联到A按钮上,点击子节点按钮会让父节点自动统计子节点的红点数量,相关的数量计算可以在生产环境中自己调整。

前缀树

在上面的实现方案中查找一个指定的红点需要从一个包含了全部红点的容器中搜索,因为是字典结构,所以在注册的红点比较少的情况下这个是够用的,但一旦数量多了起来这里面的搜索就有些慢了。因此有了通过Key键特殊命名的方式进行导航搜索的方法,例如“Mail-User-Self”,"Mail-User-Other","Mail-Syetem",这样通过前缀进行分类管理,起到在查询的时候加速的作用。

红点结构不需要改,只需要把查询调整一下就行

public class RedDotTrieSystem { public static RedDotTrieSystem Instance { get; } = new RedDotTrieSystem(); // 根节点 private RedDotNode _root; public RedDotNode Root => _root; private RedDotTrieSystem(string rootKey = "Root", string rootName = "根节点") { _root = new RedDotNode(rootKey, rootName); } // 插入节点 public RedDotNode RegisterNode(string path) { var segments = path.Split('.'); var currentNode = _root; // 逐层构建树 for (int i = 0; i < segments.Length; i++) { var segment = segments[i]; if (!currentNode.Children.ContainsKey(segment)) { var newNode = new RedDotNode(segment); currentNode.AddChild(newNode); } currentNode = currentNode.Children[segment]; } return currentNode; } /// <summary> /// 获取节点 /// </summary> public RedDotNode GetNode(string key) { var segments = key.Split('.'); var currentNode = _root; // 逐层构建树 for (int i = 0; i < segments.Length; i++) { var segment = segments[i]; if (currentNode.Children.ContainsKey(segment)) { currentNode = currentNode.Children[segment]; if (i == segments.Length - 1) { return currentNode; } } else { return null; } } return null; } /// <summary> /// 增加节点红点数量 /// </summary> public void AddNodeCount(string key, int delta = 1) { RedDotNode node = GetNode(key); if(node != null) { node.AddCount(delta); } } }

测试代码

public class RedDotTrie : MonoBehaviour { public string nodeKey; RedDotNode RedDot; public TMPro.TextMeshProUGUI redText; public Button button; void Start() { if (string.IsNullOrEmpty(nodeKey)) { return; } RedDot = RedDotTrieSystem.Instance.RegisterNode(nodeKey); RedDot.OnValueChanged += RedDot_OnValueChanged; button.onClick.AddListener(() => { RedDot.AddCount(1); }); } private void RedDot_OnValueChanged(RedDotNode node) { Debug.Log($"RedDot Node {node.Key} changed to {node.Count}"); redText.text = node.Key + " - " + node.Count.ToString(); } }

相应参数:

效果:

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询