此博客跟随siki老师的课程笔记生成,感谢siki老师的辛勤付出!
此框架功能较简单,适用于学习,可以很好的锻炼我们的设计思想
框架源码地址: UIFramework
litjson.dll下载地址: litjson


不使用UI框架存在的一些问题


1.随着游戏系统的复杂,UI控件越来越多,各个UI直接的通讯,以及UI与GameObject之间的通讯形成一张复杂的蜘蛛网,
拖着拖着,有时候我都忘了哪个对象跟哪个对象关联了。如果是别人要看我的程序,我估计他找半天都找不到UI逻辑的入口。
2.耦合性非常严重,如果要改变需求,更改某个UI或者更改某个游戏对象,那么你需要再手动全部与该对象关联的物件重新更改一次。
3.作为强迫症的程序员,最受不了程序代码的混乱。这种组织方式十分“不优雅”,看着很乱。
鉴于以上各种情况,我们需要寻找一种新的,科学的,高效的UI管理方式


UI框架总揽:



创建测试面板(非框架部分)


将面板以Prefab形式放入Resources文件夹下面,便于框架加载面板


创建json文件和UIPanelType类来保存所有的面板信息


UIPanelType.json:

{
"panelInfoList":
[
{"panelType":"MainMenu","path":"UIPanel/MainMenuPanel"},
{"panelType":"ItemMessage","path":"UIPanel/ItemMessagePanel"},
{"panelType":"Knapsack","path":"UIPanel/KnapsackPanel"},
{"panelType":"Shop","path":"UIPanel/ShopPanel"},
{"panelType":"Skill","path":"UIPanel/SkillPanel"},
{"panelType":"System","path":"UIPanel/SystemPanel"},
{"panelType":"Task","path":"UIPanel/TaskPanel"}
]
}

UIPanelType.cs:

public class UIPanelType {
public const string MainMenu = "MainMenu";
public const string Knapsack = "Knapsack";
public const string ItemMessage = "ItemMessage";
public const string Shop = "Shop";
public const string Skill = "Skill";
public const string System = "System";
public const string Task = "Task";
}

开发UIManger来解析面板信息json文件(框架核心:UIManager)


UIManager为框架的核心,全局只有一个UIManager,因此UIManager要使用单例模式
现阶段的完整的UIManager.cs(后续还会继续完善):

using System.Collections.Generic;
using System.Collections;
using System;
using UnityEngine;
using LitJson;
public class UIPanelManager
{
private static UIPanelManager _instance; public static UIPanelManager Instance
{
get
{
if (_instance == null)
{
_instance = new UIPanelManager();
}
return _instance;
}
} private Dictionary<string, string> panelPathDict;
//private Dictionary<UIPanelType,>
//private Stack<> private UIPanelManager()
{
ParseUIPanelTypeJson();
} private void ParseUIPanelTypeJson()
{
panelPathDict = new Dictionary<string, string>();
TextAsset textUIPanelType = Resources.Load<TextAsset>("UIPanelTypeJson");
UIPanelInfoList panelInfoList = JsonMapper.ToObject<UIPanelInfoList>(textUIPanelType.text); foreach (UIPanelInfo panelInfo in panelInfoList.panelInfoList)
{
panelPathDict.Add(panelInfo.panelType, panelInfo.path);
Debug.Log(panelInfo.panelType + ":" + panelInfo.path);
}
}
}

开发BasePanel抽象类(各个UIPanel的基类)


BasePanel给每个Panel定义了四个事件:
OnEnter:面板进入时调用
OnPause:面板停止时调用(鼠标与面板的交互停止)
OnResume:面板恢复使用时调用(鼠标与面板的交互恢复)
OnExit:面板退出时调用

using UnityEngine;

public abstract class BasePanel : MonoBehaviour
{
public abstract void OnEnter(); public abstract void OnPause(); public abstract void OnResume(); public abstract void OnExit(); }

给各个面板添加UIPanel类(非框架部分)

using UnityEngine;

public class MainMenuPanel : BasePanel
{ public override void OnEnter()
{
} public override void OnPause()
{
} public override void OnResume()
{
} public override void OnExit()
{
}
}

对UI面板Prefab实例化的创建与管理


获取Panel(如果panel没有被实例化,进行实例化,并且存储到已经实例化好的panel字典中)

private BasePanel GetPanel(string panelType)
{
BasePanel panel = panelDict.GetValue(panelType); //如果没有实例化面板,寻找路径进行实例化,并且存储到已经实例化好的字典面板中
if (panel == null)
{
string path = panelPathDict.GetValue(panelType);
Transform panelTransform = GameObject.Instantiate(Resources.Load<GameObject>(path), canvasTransform).transform;
panel = panelTransform.GetComponent<BasePanel>();
panelDict.Add(panelType, panel);
}
return panel;
}

字典的扩展:

using System.Collections.Generic;

public static class DictTool
{
public static Tvalue GetValue<Tkey, Tvalue>(this Dictionary<Tkey, Tvalue> dict, Tkey key)
{
Tvalue value = default(Tvalue);
dict.TryGetValue(key, out value);
return value;
}
}

现阶段的完整的UIManager.cs(后续还会继续完善):

using System.Collections.Generic;
using System.Collections;
using System;
using UnityEngine;
using LitJson;
public class UIPanelManager
{
private static UIPanelManager _instance;
private Transform canvasTransform;
private Transform CanvasTransform
{
get
{
if (canvasTransform == null)
{
canvasTransform = GameObject.Find("Canvas").transform;
}
return canvasTransform;
}
}
public static UIPanelManager Instance
{
get
{
if (_instance == null)
{
_instance = new UIPanelManager();
} return _instance;
}
} private Dictionary<string, string> panelPathDict;
private Dictionary<string, BasePanel> panelDict;
//private Stack<> private UIPanelManager()
{
ParseUIPanelTypeJson();
} private BasePanel GetPanel(string panelType)
{ if (panelDict == null)
{
panelDict = new Dictionary<string, BasePanel>();
} BasePanel panel = panelDict.GetValue(panelType); //如果没有实例化面板,寻找路径进行实例化,并且存储到已经实例化好的字典面板中
if (panel == null)
{
string path = panelPathDict.GetValue(panelType);
GameObject panelGo = GameObject.Instantiate(Resources.Load<GameObject>(path), CanvasTransform, false);
panel = panelGo.GetComponent<BasePanel>();
panelDict.Add(panelType, panel);
}
return panel;
} //解析json文件
private void ParseUIPanelTypeJson()
{
panelPathDict = new Dictionary<string, string>();
TextAsset textUIPanelType = Resources.Load<TextAsset>("UIPanelTypeJson");
UIPanelInfoList panelInfoList = JsonMapper.ToObject<UIPanelInfoList>(textUIPanelType.text); foreach (UIPanelInfo panelInfo in panelInfoList.panelInfoList)
{
panelPathDict.Add(panelInfo.panelType, panelInfo.path);
//Debug.Log(panelInfo.panelType + ":" + panelInfo.path);
}
}
}

开发界面存储栈,并进行出栈和入栈操作


【设计理念】
1.鼠标只允许和一个界面进行交互,当一个界面显示后,上一个界面要停止和鼠标的交互
2.界面显示,进行入栈操作(Push,OnEnter),停止上一个界面(OnPause)
3.界面隐藏,进行出栈操作(Pop,OnExit),恢复上一个界面(OnResume)

 private Stack<BasePanel> panelStack;
public void PushPanel(string panelType)
{
if (panelStack == null)
{
panelStack = new Stack<BasePanel>();
} //停止上一个界面
if (panelStack.Count > 0)
{
BasePanel topPanel = panelStack.Peek();
topPanel.OnPause();
} BasePanel panel = GetPanel(panelType);
panelStack.Push(panel);
panel.OnEnter();
} public void PopPanel()
{
if (panelStack == null)
{
panelStack = new Stack<BasePanel>();
}
if (panelStack.Count <= 0)
{
return;
} //退出栈顶面板
BasePanel topPanel = panelStack.Pop();
topPanel.OnExit(); //恢复上一个面板
if (panelStack.Count > 0)
{
BasePanel panel = panelStack.Peek();
panel.OnResume();
} }

控制Panel之间的跳转(非框架部分)


完善面板中的一些操作,实现面板之间的跳转,此部分不是框架部分,省略!
MainMenuPanel.cs:

using UnityEngine;
using UnityEngine.UI; public class MainMenuPanel : BasePanel
{
private Button TaskButton;
private Button KnapsackButton;
private Button SkillButton;
private Button ShopButton;
private Button SystemButton;
private CanvasGroup canvasGroup;
void Awake()
{
TaskButton = transform.Find("IconPanel/TaskButton").GetComponent<Button>();
KnapsackButton = transform.Find("IconPanel/KnapsackButton").GetComponent<Button>();
SkillButton = transform.Find("IconPanel/SkillButton").GetComponent<Button>();
ShopButton = transform.Find("IconPanel/ShopButton").GetComponent<Button>();
SystemButton = transform.Find("IconPanel/SystemButton").GetComponent<Button>();
canvasGroup = transform.GetComponent<CanvasGroup>(); TaskButton.onClick.AddListener(OnTaskButtonClick);
KnapsackButton.onClick.AddListener(OnKnapsackButtonClick);
SkillButton.onClick.AddListener(OnSkillButtonClick);
ShopButton.onClick.AddListener(OnShopButtonClick);
SystemButton.onClick.AddListener(OnSystemButtonClick);
} void OnDestory()
{
TaskButton.onClick.RemoveListener(OnTaskButtonClick);
KnapsackButton.onClick.RemoveListener(OnKnapsackButtonClick);
SkillButton.onClick.RemoveListener(OnSkillButtonClick);
ShopButton.onClick.RemoveListener(OnShopButtonClick);
SystemButton.onClick.RemoveListener(OnSystemButtonClick);
}
public override void OnEnter()
{
} public override void OnPause()
{
canvasGroup.blocksRaycasts = false;
} public override void OnResume()
{
canvasGroup.blocksRaycasts = true;
} public override void OnExit()
{
} private void OnTaskButtonClick()
{
UIPanelManager.Instance.PushPanel(UIPanelType.Task);
}
private void OnKnapsackButtonClick()
{
UIPanelManager.Instance.PushPanel(UIPanelType.Knapsack);
}
private void OnSkillButtonClick()
{
UIPanelManager.Instance.PushPanel(UIPanelType.Skill);
}
private void OnShopButtonClick()
{
UIPanelManager.Instance.PushPanel(UIPanelType.Shop);
}
private void OnSystemButtonClick()
{
UIPanelManager.Instance.PushPanel(UIPanelType.System);
}
}

UI框架(完结)



【BasePanel(基类):所有面板继承自BasePanel】
定义了四个事件:
OnEnter:面板进入时调用
OnPause:面板停止时调用(鼠标与面板的交互停止)
OnResume:面板恢复使用时调用(鼠标与面板的交互恢复)
OnExit:面板退出时调用

using UnityEngine;

public abstract class BasePanel : MonoBehaviour
{
public abstract void OnEnter();
public abstract void OnPause();
public abstract void OnResume();
public abstract void OnExit(); }

【GameRoot】
实例化游戏中的主面板

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System; public class GameRoot : MonoBehaviour {
void Start () {
UIPanelManager panelManager = UIPanelManager.Instance;
panelManager.PushPanel(UIPanelType.MainMenu);
}
}

【UIPanelManager(框架的核心,单例)】
进行解析面板信息json文件,实例化面板Prefab,面板的入栈和出栈等等一系列操作

using System.Collections.Generic;
using System.Collections;
using System;
using UnityEngine;
using LitJson;
public class UIPanelManager
{
private static UIPanelManager _instance;
private Transform canvasTransform;
private Transform CanvasTransform
{
get
{
if (canvasTransform == null)
{
canvasTransform = GameObject.Find("Canvas").transform;
}
return canvasTransform;
}
}
public static UIPanelManager Instance
{
get
{
if (_instance == null)
{
_instance = new UIPanelManager();
} return _instance;
}
} private Dictionary<string, string> panelPathDict;
private Dictionary<string, BasePanel> panelDict;
private Stack<BasePanel> panelStack; private UIPanelManager()
{
ParseUIPanelTypeJson();
} public void PushPanel(string panelType)
{
if (panelStack == null)
{
panelStack = new Stack<BasePanel>();
} //停止上一个界面
if (panelStack.Count > 0)
{
BasePanel topPanel = panelStack.Peek();
topPanel.OnPause();
} BasePanel panel = GetPanel(panelType);
panelStack.Push(panel);
panel.OnEnter();
} public void PopPanel()
{
if (panelStack == null)
{
panelStack = new Stack<BasePanel>();
}
if (panelStack.Count <= 0)
{
return;
} //退出栈顶面板
BasePanel topPanel = panelStack.Pop();
topPanel.OnExit(); //恢复上一个面板
if (panelStack.Count > 0)
{
BasePanel panel = panelStack.Peek();
panel.OnResume();
} } private BasePanel GetPanel(string panelType)
{ if (panelDict == null)
{
panelDict = new Dictionary<string, BasePanel>();
} BasePanel panel = panelDict.GetValue(panelType); //如果没有实例化面板,寻找路径进行实例化,并且存储到已经实例化好的字典面板中
if (panel == null)
{
string path = panelPathDict.GetValue(panelType);
GameObject panelGo = GameObject.Instantiate(Resources.Load<GameObject>(path), CanvasTransform, false);
panel = panelGo.GetComponent<BasePanel>();
panelDict.Add(panelType, panel);
}
return panel;
} //解析json文件
private void ParseUIPanelTypeJson()
{
panelPathDict = new Dictionary<string, string>();
TextAsset textUIPanelType = Resources.Load<TextAsset>("UIPanelTypeJson");
UIPanelInfoList panelInfoList = JsonMapper.ToObject<UIPanelInfoList>(textUIPanelType.text); foreach (UIPanelInfo panelInfo in panelInfoList.panelInfoList)
{
panelPathDict.Add(panelInfo.panelType, panelInfo.path);
//Debug.Log(panelInfo.panelType + ":" + panelInfo.path);
}
}
}

【litjson】
json文件解析的工具

【UIPanelTypeJson(保存面板信息的json文件)】
1.此文件需要加载,保存到Resources文件下
2.保存了面板的类型(相当于名称)和面板Prefab的路径(实例化面板时要用到)
3.每添加一个面板,都要在此文件添加该面板对应的信息

{
"panelInfoList":
[
{"panelType":"MainMenu","path":"UIPanel/MainMenuPanel"},
{"panelType":"ItemMessage","path":"UIPanel/ItemMessagePanel"},
{"panelType":"Knapsack","path":"UIPanel/KnapsackPanel"},
{"panelType":"Shop","path":"UIPanel/ShopPanel"},
{"panelType":"Skill","path":"UIPanel/SkillPanel"},
{"panelType":"System","path":"UIPanel/SystemPanel"},
{"panelType":"Task","path":"UIPanel/TaskPanel"}
]
}

【DictTool】
Dictionnary的拓展工具类

using System.Collections.Generic;

public static class DictTool
{
public static Tvalue GetValue<Tkey, Tvalue>(this Dictionary<Tkey, Tvalue> dict, Tkey key)
{
Tvalue value = default(Tvalue);
dict.TryGetValue(key, out value);
return value;
}
}

【UIPanelInfo(面板的信息类)】
包括面板的名称和面板Prefab的路径
用于和json文件进行映射

using System;
[Serializable]
public class UIPanelInfo
{
public string panelType;
public string path; public UIPanelInfo()
{ }
}

【UIPanelInfoList(面板信息集合类)】
用于和json文件进行映射

using System;
using System.Collections.Generic; [Serializable]
public class UIPanelInfoList
{
public List<UIPanelInfo> panelInfoList; public UIPanelInfoList() { }
}

【UIPanelType(面板的类型)】
用来记录面板的类型(名称)
每添加一个面板都要在此类里面添加对应面板的类型

public class UIPanelType {
public const string MainMenu = "MainMenu";
public const string Knapsack = "Knapsack";
public const string ItemMessage = "ItemMessage";
public const string Shop = "Shop";
public const string Skill = "Skill";
public const string System = "System";
public const string Task = "Task";
}

(完)

---------------------
作者:cchoop
来源:CSDN
原文:https://blog.csdn.net/qq_34937637/article/details/80374387

(转载)基于Unity~UGUI的简单UI框架(附UIFramework源码)的更多相关文章

  1. 基于struts2的学生报道管理系统(附github源码地址)

    本项目参考了<java web轻量级开发全体验>,加入了对mysql的支持. 一.基本业务功能 通过struts2框架,结合mysql数据库构建一个学生报到管理系统,来模拟学生报到登记的过 ...

  2. 基于 Vue.js 之 iView UI 框架非工程化实践记要

    像我们平日里做惯了 Java 或者 .NET 这种后端程序员,对于前端的认识还常常停留在 jQuery 时代,包括其插件在需要时就引用一下,不需要就删除.故观念使然,尽管 Nuget 和 Maven ...

  3. 基于 Vue.js 之 iView UI 框架非工程化实践记要 使用 Newtonsoft.Json 操作 JSON 字符串 基于.net core实现项目自动编译、并生成nuget包 webpack + vue 在dev和production模式下的小小区别 这样入门asp.net core 之 静态文件 这样入门asp.net core,如何

    基于 Vue.js 之 iView UI 框架非工程化实践记要   像我们平日里做惯了 Java 或者 .NET 这种后端程序员,对于前端的认识还常常停留在 jQuery 时代,包括其插件在需要时就引 ...

  4. Spring框架之spring-webmvc源码完全解析

    Spring框架之spring-webmvc源码完全解析 Spring框架提供了构建Web应用程序的全功能MVC模块.Spring MVC分离了控制器.模型对象.分派器以及处理程序对象的角色,支持多种 ...

  5. Spring框架之beans源码完全解析

    导读:Spring可以说是Java企业开发里最重要的技术.而Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Oriented Programmin ...

  6. Spring框架之AOP源码完全解析

    Spring框架之AOP源码完全解析 Spring可以说是Java企业开发里最重要的技术.Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Orie ...

  7. Spring框架之jms源码完全解析

    Spring框架之jms源码完全解析 我们在前两篇文章中介绍了Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Oriented Programmi ...

  8. Spring框架之jdbc源码完全解析

    Spring框架之jdbc源码完全解析 Spring JDBC抽象框架所带来的价值将在以下几个方面得以体现: 1.指定数据库连接参数 2.打开数据库连接 3.声明SQL语句 4.预编译并执行SQL语句 ...

  9. Spring框架之websocket源码完全解析

    Spring框架之websocket源码完全解析 Spring框架从4.0版开始支持WebSocket,先简单介绍WebSocket协议(详细介绍参见"WebSocket协议中文版" ...

随机推荐

  1. Nestjs 链接mysql

    文档 下插件 λ yarn add @nestjs/typeorm typeorm mysql 创建 cats模块, 控制器,service λ nest g mo cats λ nest g co ...

  2. javascript 缩写技巧

    19种JS高(炫)效(技)缩写法 https://segmentfault.com/a/1190000011229633

  3. 东大oj1155 等凹函数

    Problem Description 定义一种数字称为等凹数字,即从高位到低位,每一位的数字先递减再递增,且该数是一个回文数,即从左读到右与从右读到左是一样的,仅形成一个等凹峰,如543212345 ...

  4. word2vec生成词向量和字向量

    生成字符向量的过程中需要注意: 1)在收集数据生成corpus时候,通过Word2Vec生成字向量的时候,产生了“ ”空格字符向量,但是加载模型是不会成功的.那么你不是生成的binary文件,就可以修 ...

  5. js 事件模型

    说到事件,就要追溯到网景与微软的“浏览器大战”了.当时,事件模型还没有标准,两家公司的实现就是事实标准.网景在Navigator中实现了“事件捕获”的事件系统,而微软则在IE中实现了一个基本上相反的事 ...

  6. MAC OSX Xcode硬盘清理

    1.移除对旧设备的支持影响:可重新生成:再连接旧设备调试时,会重新自动生成.我移除了4.3.2, 5.0, 5.1等版本的设备支持.路径:~/Library/Developer/Xcode/iOS D ...

  7. vue-property-decorator 提供 OO 的风格 Vue Component 方便类型声明

    @Prop  父子组件之间传值 Install: npm install --save vue-property-decorator Child: <template> <div&g ...

  8. C++——创建类的时候用new与不用new 的区别(转)

    C++在创建对象的时候可以采用两种方式:(例如类名为Test) Test test  或者 Test* pTest = new Test().        这两种方法都可以实例化一个对象,但是这两种 ...

  9. 在 Django/Flask 开发服务器上使用 HTTPS

    使用 Django 或 Flask 这种框架开发 web app 的时候一般都会用内建服务器开发和调试程序,等程序完成后再移交到生产环境部署.问题是这些内建服务器通常都不支持 HTTPS,我们想在开发 ...

  10. 对Java代码加密的两种方式,防止反编译

    使用Virbox Protector对Java项目加密有两种方式,一种是对War包加密,一种是对Jar包加密.Virbox Protector支持这两种文件格式加密,可以加密用于解析class文件的j ...