红点系统

红点功能需求:

  1. 根据服务端数据增加、移出红点
  2. UI可以监听红点变动,刷新红点UI
  3. 红点有层级关系,子节点有红点的时候父节点继续有红点,根据这个需求,可以将红点设计成树状结构。

首先定义红点节点类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System.Collections.Generic;

internal class RedPointNode
{
public string Path;
public RedPointNode Parent;

private List<RedPointNode> _childrenList = new List<RedPointNode>();

/// <summary>
/// 删除子节点
/// </summary>
/// <param name="node"></param>
public void RemoveChild(RedPointNode node)
{
_childrenList.Remove(node);
RedPointManager.Instance.OnNodeRemoved(node);

if (_childrenList.Count == 0)
{
Parent?.RemoveChild(this);
}
else
{
RedPointManager.Instance.OnNodeChanged(this);
}
}

/// <summary>
/// 加节点
/// </summary>
/// <param name="parentPath"></param>
/// <param name="nodeNameList"></param>
/// <param name="index"></param>
public void AddNode(string parentPath, string[] nodeNameList, int index)
{
if (index >= nodeNameList.Length)
{
return;
}

string name = nodeNameList[index];
string path = parentPath + "/" + name;
var node = _childrenList.Find(x => x.Path == path);
if (node == null)
{
node = new RedPointNode()
{
Path = path,
Parent = this
};
_childrenList.Add(node);

RedPointManager.Instance.OnNodeAdded(node);
}

node.AddNode(path, nodeNameList, ++index);
}
}

红点管理类,是一个单例,对外暴露操作接口。
外层使用的时候在界面打开的时候通过HasRedPoint设置红点状态,同时通过AddListener增加监听,回调里面继续调用HasRedPoint设置红点状态即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
using Babu.Client;
using System;
using System.Collections.Generic;

/// <summary>
/// 红点管理类
/// </summary>
internal class RedPointManager : ModuleSingleton<RedPointManager>, IModule
{
RedPointNode _root = new RedPointNode();

private Dictionary<string, RedPointNode> _redPointNodeDict = new Dictionary<string, RedPointNode>();
Dictionary<string, List<Action>> _callbackDict = new Dictionary<string, List<Action>>();

public void OnCreate(object createParam)
{
_root.Path = "root";
_redPointNodeDict.Add(_root.Path, _root);
}

public void OnDestroy()
{
}

public void OnUpdate()
{
}

/// <summary>
/// 增加红点
/// </summary>
/// <param name="path"></param>
public void AddRedPoint(string path)
{
if (path.StartsWith("root") == false)
{
path = "root/" + path;
}

_root.AddNode("root", path.Split("/"), 1);

var node = _redPointNodeDict[path];
OnNodeChanged(node);
}

/// <summary>
/// 删除红点
/// </summary>
/// <param name="path"></param>
public void RemoveRedPoint(string path)
{
if (path.StartsWith("root") == false)
{
path = "root/" + path;
}

if (_redPointNodeDict.TryGetValue(path, out var node))
{
node.Parent?.RemoveChild(node);
}
}

/// <summary>
/// 路径是否有红点
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public bool HasRedPoint(string path)
{
if (path.StartsWith("root") == false)
{
path = "root/" + path;
}

return _redPointNodeDict.ContainsKey(path);
}

/// <summary>
/// 增加红点监听
/// </summary>
/// <param name="path"></param>
/// <param name="callback"></param>
public void AddListener(string path, Action callback)
{
if (path.StartsWith("root") == false)
{
path = "root/" + path;
}

if (_callbackDict.TryGetValue(path, out var list))
{
list.Add(callback);
}
else
{
list = new List<Action>() { callback };
_callbackDict.Add(path, list);
}
}

/// <summary>
/// 移出监听
/// </summary>
/// <param name="path"></param>
/// <param name="callback"></param>
public void RemoveListener(string path, Action callback)
{
if (path.StartsWith("root") == false)
{
path = "root/" + path;
}

if (_callbackDict.TryGetValue(path, out var list))
{
list.Remove(callback);
if (list.Count == 0)
{
_callbackDict.Remove(path);
}
}
}


/// <summary>
/// 节点增加
/// </summary>
/// <param name="node"></param>
public void OnNodeAdded(RedPointNode node)
{
_redPointNodeDict[node.Path] = node;
}

/// <summary>
/// 节点删除
/// </summary>
/// <param name="node"></param>
public void OnNodeRemoved(RedPointNode node)
{
_redPointNodeDict.Remove(node.Path);

if (_callbackDict.TryGetValue(node.Path, out var list))
{
for (int i = 0; i < list.Count; i++)
{
list[i].Invoke();
}
}
}

/// <summary>
/// 节点变更
/// </summary>
/// <param name="node"></param>
public void OnNodeChanged(RedPointNode node)
{
if (node == null)
{
return;
}

if (_callbackDict.TryGetValue(node.Path, out var list))
{
for (int i = 0; i < list.Count; i++)
{
list[i].Invoke();
}
}

OnNodeChanged(node.Parent);
}
}