435 lines
10 KiB
Markdown
435 lines
10 KiB
Markdown
# UI系统优化建议
|
||
|
||
## 1. UI框架优化
|
||
|
||
### 1.1 当前实现
|
||
```csharp
|
||
// UIFightTeamController.cs 中的UI实现
|
||
public class UIFightTeamController : UIWindow
|
||
{
|
||
private List<uint> _displayList;
|
||
private List<GameObject> _headList;
|
||
private bool _isInit = false;
|
||
|
||
public override void OnInit()
|
||
{
|
||
UIFightTeamBinder.GetComponents(this);
|
||
_OnInit();
|
||
}
|
||
|
||
protected override void OnShowWindow(object data = null)
|
||
{
|
||
if (_isInit)
|
||
{
|
||
_isInit = false;
|
||
return;
|
||
}
|
||
_SetData();
|
||
_Refresh();
|
||
}
|
||
}
|
||
```
|
||
|
||
### 1.2 优化建议
|
||
1. UI组件化和对象池优化:
|
||
```csharp
|
||
// UI组件基类
|
||
public abstract class UIComponent : MonoBehaviour
|
||
{
|
||
protected UIData _data;
|
||
protected bool _initialized;
|
||
|
||
public virtual void Init()
|
||
{
|
||
if (_initialized) return;
|
||
_initialized = true;
|
||
OnInit();
|
||
}
|
||
|
||
protected virtual void OnInit() { }
|
||
|
||
public virtual void SetData(UIData data)
|
||
{
|
||
_data = data;
|
||
Refresh();
|
||
}
|
||
|
||
public virtual void Refresh() { }
|
||
}
|
||
|
||
// UI对象池管理
|
||
public class UIPoolManager
|
||
{
|
||
private Dictionary<string, Queue<GameObject>> _pools = new();
|
||
private Dictionary<string, GameObject> _prefabs = new();
|
||
|
||
public T GetUI<T>(string prefabPath) where T : UIComponent
|
||
{
|
||
if (!_pools.ContainsKey(prefabPath))
|
||
_pools[prefabPath] = new Queue<GameObject>();
|
||
|
||
if (_pools[prefabPath].Count > 0)
|
||
{
|
||
var go = _pools[prefabPath].Dequeue();
|
||
go.SetActive(true);
|
||
return go.GetComponent<T>();
|
||
}
|
||
|
||
return CreateUI<T>(prefabPath);
|
||
}
|
||
|
||
public void ReturnUI(string prefabPath, GameObject ui)
|
||
{
|
||
ui.SetActive(false);
|
||
_pools[prefabPath].Enqueue(ui);
|
||
}
|
||
}
|
||
|
||
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
|
||
{
|
||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||
}
|
||
}
|
||
|
||
// 战斗UI的ViewModel
|
||
public class FightTeamViewModel : ViewModel
|
||
{
|
||
private ObservableCollection<UnitViewModel> _units = new();
|
||
public ObservableCollection<UnitViewModel> Units => _units;
|
||
|
||
private UnitViewModel _selectedUnit;
|
||
public UnitViewModel SelectedUnit
|
||
{
|
||
get => _selectedUnit;
|
||
set
|
||
{
|
||
_selectedUnit = value;
|
||
NotifyPropertyChanged();
|
||
}
|
||
}
|
||
}
|
||
|
||
// UI View层
|
||
public class UIFightTeamView : UIWindow
|
||
{
|
||
private FightTeamViewModel _viewModel;
|
||
|
||
public override void OnInit()
|
||
{
|
||
_viewModel = new FightTeamViewModel();
|
||
InitializeBindings();
|
||
}
|
||
|
||
private void InitializeBindings()
|
||
{
|
||
// 数据绑定
|
||
_viewModel.PropertyChanged += OnViewModelPropertyChanged;
|
||
}
|
||
}
|
||
```
|
||
|
||
## 2. UI性能优化
|
||
|
||
### 2.1 列表优化
|
||
使用对象池和虚拟列表优化长列表:
|
||
```csharp
|
||
public class VirtualizedList<T> : MonoBehaviour where T : MonoBehaviour
|
||
{
|
||
[SerializeField] private RectTransform _viewport;
|
||
[SerializeField] private RectTransform _content;
|
||
[SerializeField] private T _itemPrefab;
|
||
|
||
private List<T> _activeItems = new();
|
||
private Queue<T> _pooledItems = new();
|
||
private List<IItemData> _dataList = new();
|
||
|
||
public void SetData(List<IItemData> dataList)
|
||
{
|
||
_dataList = dataList;
|
||
UpdateVisibleItems();
|
||
}
|
||
|
||
private void UpdateVisibleItems()
|
||
{
|
||
// 计算可见区域
|
||
var viewportBounds = new Bounds(_viewport.position, _viewport.rect.size);
|
||
|
||
// 回收不可见项
|
||
for (int i = _activeItems.Count - 1; i >= 0; i--)
|
||
{
|
||
var item = _activeItems[i];
|
||
if (!viewportBounds.Intersects(item.GetComponent<RectTransform>().bounds))
|
||
{
|
||
ReturnToPool(item);
|
||
_activeItems.RemoveAt(i);
|
||
}
|
||
}
|
||
|
||
// 创建可见项
|
||
foreach (var data in _dataList)
|
||
{
|
||
if (IsItemVisible(data) && !IsItemCreated(data))
|
||
{
|
||
CreateItem(data);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2.2 UI资源加载优化
|
||
使用异步加载和预加载机制:
|
||
```csharp
|
||
public class UIResourceManager : MonoBehaviour
|
||
{
|
||
private Dictionary<string, WeakReference<GameObject>> _uiCache = new();
|
||
private HashSet<string> _preloadList = new();
|
||
|
||
public async UniTask PreloadUI(string uiName)
|
||
{
|
||
if (_preloadList.Contains(uiName)) return;
|
||
|
||
var prefab = await LoadUIPrefabAsync(uiName);
|
||
_uiCache[uiName] = new WeakReference<GameObject>(prefab);
|
||
_preloadList.Add(uiName);
|
||
}
|
||
|
||
public async UniTask<GameObject> GetUI(string uiName)
|
||
{
|
||
if (_uiCache.TryGetValue(uiName, out var weakRef))
|
||
{
|
||
if (weakRef.TryGetTarget(out var cachedUI))
|
||
{
|
||
return cachedUI;
|
||
}
|
||
}
|
||
|
||
return await LoadUIPrefabAsync(uiName);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 3. UI事件系统优化
|
||
|
||
### 3.1 当前问题
|
||
- GameObject查找性能开销
|
||
- 组件获取方式不优化
|
||
- 事件系统使用不规范
|
||
|
||
### 3.2 优化建议
|
||
1. 优化组件获取:
|
||
```csharp
|
||
public class UIUtils
|
||
{
|
||
// 缓存组件查找结果
|
||
private static Dictionary<int, Dictionary<Type, Component>> _componentCache = new();
|
||
|
||
public static T GetComponent<T>(GameObject go) where T : Component
|
||
{
|
||
var instanceId = go.GetInstanceID();
|
||
var type = typeof(T);
|
||
|
||
if (!_componentCache.ContainsKey(instanceId))
|
||
_componentCache[instanceId] = new Dictionary<Type, Component>();
|
||
|
||
if (!_componentCache[instanceId].ContainsKey(type))
|
||
_componentCache[instanceId][type] = go.GetComponent<T>();
|
||
|
||
return _componentCache[instanceId][type] as T;
|
||
}
|
||
|
||
public static void ClearCache(GameObject go)
|
||
{
|
||
var instanceId = go.GetInstanceID();
|
||
if (_componentCache.ContainsKey(instanceId))
|
||
_componentCache.Remove(instanceId);
|
||
}
|
||
}
|
||
```
|
||
|
||
2. 优化事件系统使用:
|
||
```csharp
|
||
public class UIEventHandler : MonoBehaviour
|
||
{
|
||
private List<UIEventRegistration> _registrations = new();
|
||
|
||
protected void RegisterEvent<T>(string eventName, Action<T> handler)
|
||
{
|
||
var registration = new UIEventRegistration
|
||
{
|
||
eventName = eventName,
|
||
unregisterAction = () => EventManager.Instance.Unregister(eventName, handler)
|
||
};
|
||
|
||
EventManager.Instance.Register(eventName, handler);
|
||
_registrations.Add(registration);
|
||
}
|
||
|
||
protected virtual void OnDestroy()
|
||
{
|
||
foreach (var registration in _registrations)
|
||
{
|
||
registration.unregisterAction?.Invoke();
|
||
}
|
||
_registrations.Clear();
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.2 优化建议
|
||
1. 实现UI事件管理器:
|
||
```csharp
|
||
public class UIEventManager
|
||
{
|
||
private Dictionary<Type, HashSet<IUIEventHandler>> _eventHandlers = new();
|
||
|
||
public void Register<T>(IUIEventHandler handler) where T : IUIEvent
|
||
{
|
||
var type = typeof(T);
|
||
if (!_eventHandlers.ContainsKey(type))
|
||
{
|
||
_eventHandlers[type] = new HashSet<IUIEventHandler>();
|
||
}
|
||
_eventHandlers[type].Add(handler);
|
||
}
|
||
|
||
public void Unregister<T>(IUIEventHandler handler) where T : IUIEvent
|
||
{
|
||
var type = typeof(T);
|
||
if (_eventHandlers.TryGetValue(type, out var handlers))
|
||
{
|
||
handlers.Remove(handler);
|
||
}
|
||
}
|
||
|
||
public void Dispatch<T>(T uiEvent) where T : IUIEvent
|
||
{
|
||
var type = typeof(T);
|
||
if (_eventHandlers.TryGetValue(type, out var handlers))
|
||
{
|
||
foreach (var handler in handlers)
|
||
{
|
||
handler.Handle(uiEvent);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 4. UI动画系统优化
|
||
|
||
### 4.1 实现动画状态机:
|
||
```csharp
|
||
public class UIAnimationStateMachine
|
||
{
|
||
private Dictionary<string, UIAnimationState> _states = new();
|
||
private UIAnimationState _currentState;
|
||
|
||
public async UniTask TransitionTo(string stateName, bool immediate = false)
|
||
{
|
||
if (_currentState != null)
|
||
{
|
||
await _currentState.Exit(immediate);
|
||
}
|
||
|
||
if (_states.TryGetValue(stateName, out var newState))
|
||
{
|
||
_currentState = newState;
|
||
await _currentState.Enter(immediate);
|
||
}
|
||
}
|
||
}
|
||
|
||
public class UIAnimationState
|
||
{
|
||
private List<UIAnimation> _animations = new();
|
||
|
||
public async UniTask Enter(bool immediate)
|
||
{
|
||
foreach (var anim in _animations)
|
||
{
|
||
if (immediate)
|
||
anim.Complete();
|
||
else
|
||
await anim.Play();
|
||
}
|
||
}
|
||
|
||
public async UniTask Exit(bool immediate)
|
||
{
|
||
foreach (var anim in _animations)
|
||
{
|
||
if (immediate)
|
||
anim.Complete();
|
||
else
|
||
await anim.Reverse();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 5. UI响应式布局优化
|
||
|
||
### 5.1 实现响应式布局系统:
|
||
```csharp
|
||
public class ResponsiveLayout : MonoBehaviour
|
||
{
|
||
[SerializeField] private List<BreakPoint> _breakPoints = new();
|
||
[SerializeField] private List<LayoutConfig> _configs = new();
|
||
|
||
private void OnRectTransformDimensionsChange()
|
||
{
|
||
UpdateLayout();
|
||
}
|
||
|
||
private void UpdateLayout()
|
||
{
|
||
var currentWidth = GetComponent<RectTransform>().rect.width;
|
||
var config = GetConfigForWidth(currentWidth);
|
||
ApplyConfig(config);
|
||
}
|
||
|
||
private void ApplyConfig(LayoutConfig config)
|
||
{
|
||
// 应用布局配置
|
||
foreach (var element in config.elements)
|
||
{
|
||
ApplyElementLayout(element);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 6. UI优化建议总结
|
||
|
||
### 6.1 架构优化
|
||
- 实现MVVM架构
|
||
- 统一UI事件系统
|
||
- 规范UI生命周期管理
|
||
|
||
### 6.2 性能优化
|
||
- 使用对象池
|
||
- 实现虚拟列表
|
||
- 优化UI资源加载
|
||
|
||
### 6.3 开发效率
|
||
- 完善UI工具链
|
||
- 标准化UI组件
|
||
- 自动化UI测试
|
||
|
||
### 6.4 后续优化方向
|
||
1. UI框架
|
||
- 实现完整的MVVM框架
|
||
- 优化UI导航系统
|
||
- 增加UI单元测试
|
||
|
||
2. 性能优化
|
||
- 实现UI合批
|
||
- 优化UI重建
|
||
- 减少UI重绘
|
||
|
||
3. 工具链
|
||
- UI编辑器扩展
|
||
- UI自动化测试
|
||
- UI性能分析工具
|