using System.Collections.Generic; using Base; using Logging; using Prefab; using TMPro; using UnityEngine; using UnityEngine.UI; // 假设 TextPrefab 在 Prefab 命名空间下 // 假设 TextPrefab 内部使用了 TextMeshPro namespace UI { public class LogUI : FullScreenUI { // 日志类型颜色映射 private static readonly Dictionary logColors = new() { { LogType.Log, Color.white }, { LogType.Warning, Color.yellow }, { LogType.Error, new Color(1f, 0.4f, 0.4f) }, { LogType.Exception, new Color(1f, 0.2f, 0.2f) }, { LogType.Assert, new Color(0.8f, 0.4f, 1f) } }; public Transform contentPanel; // 日志内容容器 public TextPrefab textPrefab; // 文本预制体引用 public Toggle pauseToggle; // 逻辑修改:将_logItems改为存储TextPrefab实例,避免频繁GetComponent private readonly List _logItems = new(); // 已创建的日志条目 private int _lastLogCount; // 上次显示的日志数量 // 逻辑修改:在Update中周期性检查日志数量变化并刷新UI private void Update() { // 获取当前LogCapturer中的日志数量(最旧在前) var currentCapturerLogCount = LogCapturer.GetLogs(false).Count; if (_lastLogCount != currentCapturerLogCount) RefreshLogDisplay(); } // 逻辑修改:添加OnDestroy方法来清理动态创建的UI元素 private void OnDestroy() { if (_logItems != null) { foreach (var item in _logItems) // 检查item及其gameObject是否仍有效,以防在其他地方已经被销毁或为空 if (item != null && item.gameObject != null) Destroy(item.gameObject); _logItems.Clear(); // 清空列表引用 } } public override void Show() { base.Show(); pauseToggle.isOn = needPause; RefreshLogDisplay(); // 首次显示时刷新 } private void RefreshLogDisplay() { // 逻辑修改:获取"最旧在前,最新在后"的日志列表,与UI显示顺序匹配 var currentLogsInCapturer = LogCapturer.GetLogs(false); var newLogCount = currentLogsInCapturer.Count; var existingUiItemCount = _logItems.Count; // 逻辑修改:处理日志数量减少的情况(日志被从LogCapturer的队列前端移除,即最旧的日志) if (newLogCount < existingUiItemCount) { // 计算需要移除的UI条目数量 var itemsToRemove = existingUiItemCount - newLogCount; // 从_logItems的开头移除(销毁最旧的UI元素) for (var i = 0; i < itemsToRemove; i++) // 确保销毁对应的GameObject,避免内存泄露 Destroy(_logItems[i].gameObject); _logItems.RemoveRange(0, itemsToRemove); // 从列表中移除引用 } // 逻辑修改:处理日志数量增加的情况(LogCapturer中新增日志) else if (newLogCount > existingUiItemCount) { // 从现有UI条目数量开始,创建新的UI条目,并添加到_logItems末尾 for (var i = existingUiItemCount; i < newLogCount; i++) CreateLogEntry(currentLogsInCapturer[i]); // 创建并添加新的UI元素,会自动追加到_logItems } // 逻辑修改:更新所有现有/剩余的UI条目内容,确保与LogCapturer中的数据一致 // 这一步确保了UI元素能准确反映其对应的日志数据,处理了任何可能的日志内容更新或初始设置。 for (var i = 0; i < newLogCount; i++) UpdateLogEntry(_logItems[i], currentLogsInCapturer[i]); _lastLogCount = newLogCount; // 更新上次显示的日志数量 } private void CreateLogEntry(LogCapturer.LogEntry entry) { // 实例化文本预制体,并将其添加到内容面板 var logItem = Instantiate(textPrefab, contentPanel); _logItems.Add(logItem); // 逻辑修改:直接添加TextPrefab实例 UpdateLogEntry(logItem, entry); // 逻辑修改:直接传入TextPrefab实例进行更新 } // 逻辑修改:UpdateLogEntry现在直接接收TextPrefab实例,更高效 private void UpdateLogEntry(TextPrefab logItem, LogCapturer.LogEntry entry) { // 设置文本内容 logItem.Label = entry.ToString(); // 设置文本颜色(根据日志类型) if (logColors.TryGetValue(entry.Type, out var color)) logItem.text.color = color; else logItem.text.color = Color.white; // 默认颜色 logItem.text.alignment = TextAlignmentOptions.TopLeft; } public void HideCallback() { UIInputControl.Instance.Hide(this); } public void SetPauseCallback() { needPause = pauseToggle.isOn; Clock.Instance.Pause = needPause; } } }