UI框架
解决的问题
- 解决找对象问题
- 交互事件管理
- 模态处理
- 语言本地化
解决办法
- 关于找对象问题
- 要UI的统一管理 如果有一个UI管理,当需要找的时候直接通过UI管理就能找到
- 交互事件
- 通用事件管理 解决消息管理传递 消息框架
- 模态
- UI的层次模块管理
- 本地化
- 文本多语言管理
写UI框架前准备
配置文件 XML/JSON/数据库/表格 一般都用XML/JSON 方便管理
对象池脚本
资源管理脚本
单例管理脚本
正式开写框架
看框架时候要结合之前写的设计模式和设计原则这篇博客,里边设计模式,简单工厂模式 AssetsManager看
也可以打开这篇博客直接ctrl+f 输入AssetsManager
UIManager
using Utility;
using System.Collections.Generic;
namespace UIFrame {
//UI管理器 最核心的功能
public class UIManager : Singleton<UIManager> {
private UIManager(){
//定义完后在构造函数中new
uiModules = new Dictionary<string,UIModuleBase>();
canvas = GameObject.FindWithTag("Canvas").transform;
uiModuleStack = new Stack<UIModuleBase>();
}
/*
容器型数据结构:
Array ArrayList List<> Dictionary<k,v> HashTable
Stack<> Queue<> Link(链表) Tree(数) 图
*/
//别忘了在unity里添加标签 给canvas装上标签
//画布对象
private Transform canvas;
//所管理的所有UI模块 模块名 路径
private Dictionary<string,UIModuleBase> uiModules;
//模块加载顺序 栈
//UI模块栈
private Stack<UIModuleBase> uiModuleStack;
#regine Find Module Widget
//跨模块获取某个元件【确保要找的模块已经被加载】
public UIWidgetBase FindWidget(string moduleName,string widgetName){
//判断模块名称是否存在
if(!uiModules.ContainsKey(moduleName) || uiModules[moduleName] == null){
Debug.LogError("该模块不存在");
return null;
}
//通过模块去获取相应的元件
return uiModules[moduleName].FindCurrentModuleWidget(widgetName);
}
#endregine
#regine Load / Unload Module
//模块的管理 添加模块 移除模块
//加载 需要配置文件
//在unity里 创建Resources文件夹
//然后在里面在创建一个Configuration文件夹
//在创建一个文件ModulePathConfig.json
//加载模块
private void LoadModule(string moduleName,Vector2 anchoredPosition){
//判断字典里有没有该模块,或字典里该模块的值为空
//没有key value 或者 没有 value
if(!uiModules.ContainsKey(moduleName) || uiModules[moduleName] == null){
//通过模块名称获取资源路径
string panelPath = UIConfigurationManager.GetInstance().
GetPanelPrefabPathByname(moduleName);
//加载预设体,并生成对应的对象
GameObject module = PrefabManager.GetInstance().
CreateGameObjectByPrefab(panelPath,canvas,anchoredPosition);
//修改模块名称,去掉(Clone)
module.name = moduleName;
//获取模块组件
UIModuleBase moduleBase = module.GetComponent<UIModuleBase>();
//添加到字典里
uiModules[moduleName] = moduleBase;
}
}
//卸载模块
private void UnloadModule(string moduleName){
//判断字典里有没有这个名字
if(!uiModules.ContainsKey(moduleName)){
Debug.LogError("当前模块不存在,不能卸载");
return;
}
//如果存在 先拿到这模块
UIModuleBase moduleBase = uiModules[moduleName];
//从字典移除
uiModules.Remove(moduleName);
//销毁该对象
Object.Destroy(moduleBase.gameObject);
}
#endregine
#regine 单窗口模式 栈型管理
//进栈 把一个模块压栈
public void PushModule(string moduleName){
//加载该模块
LoadModule(moduleName,Vector2.zero);//Vector2 写外面是方便多窗口的时候可以自己调整
//判断是不是单窗口
if(uiModules[moduleName].uiModuleMode == UIModuleMode.MultipleControlMode){
Debug.LogError("当前窗口为多窗口模式,使用OpenModule打开");
UnloadModule(moduleName);
return;
}
//栈里是否有模块存在
if(uiModuleStack.Count != 0){
//栈顶模块执行暂停方法
uiModuleStack.peek().OnPause();
}
//新模块压栈
uiModuleStack.Push(uiModules[moduleName]);
//新模块执行打开的方法
uiModuleStack.Peek().OnOpen();
}
//出栈 栈顶模块出栈
public void PopModule(){
//判断一下栈里有没有东西 没有直接return
if(uiModuleStack.Count == 0)
return;
//栈顶模块出栈
uiModuleStack.Pop().OnClose();
//恢复栈顶下面的模块
//判断一下栈里有没有东西 没有直接return
if(uiModuleStack.Count == 0)
return;
//新的栈顶模块执行恢复方法
uiModuleStack.Peek().OnResume();
}
#endregine
#regine 多窗口模式 字典管理
//打开多窗口模式的模块
public void OpenModule(string moduleName,Vector2 anchoredPosition){
//加载该模块
LoadModule(moduleName,anchoredPosition);
if(uiModules[moduleName].uiModuleMode == UIModuleMode.SingleControlMode){
Debug.LogError("当前窗口为单窗口模式,使用PushModule打开");
UnloadModule(moduleName);
return;
}
//执行打开方法
uiModules[moduleName].OnOpen();
}
//关闭多窗口模式的模块
public void CloseModule(string moduleName){
if(!uiModules.ContainsKey(moduleName)){
Debug.LogError("当前模块不存在,不能关闭");
return;
}
//执行关闭
uiModules[moduleName].OnClose();
}
#endregine
}
}
UIModuleBase
解决字典里value是GameObject的问题
using UnityEngine;
namespace UIFrame {
//抽象 要挂载在模块的根对象上
//UI模块基类
[RequireComponent(typeof(CanvasGroup))]//继承该脚本必须绑定上这个组件
public class UIModuleBase : MonoBehaviour {
//存储当前模块的UI元件 (UI元件:每个模块当中需要访问和交互的UI对象)
private Dictionary<string,UIWidgetBase> uiWidgets;
//UI模块的控制模式
public UIModuleMode uiModuleMode = UIModuleMode.SingleControlMode;
protected CanvasGroup canvasGroup;
//当前模块的元件脚本
//这个字符串要判断
//这个脚本存不存在
//这个脚本是不是U