简单的UI框架(单例脚本)

单例脚本

Singleton.cs

using System;

/// <summary>
/// 
/// 使用方法:
/// 1.需要单例的类继承Singleton<T>
/// 例如:class UIManager:Singleton<UIManager>
/// 
/// 2.在代码内调用一次 UIManager.Init();
/// 之后即可使用UIManager.Instance调用单例
///
/// 3.Panel预制物需添加Canvas Group组件
/// 
/// </summary>
/// <typeparam name="T"></typeparam>
public class Singleton<T> where T : new() {
	private static T singleton = default;
	private static readonly object monitorLock = new object();

	public static T Instance {
		get {
			if (singleton == null) {
				//Monitor Class:提供同步访问对象的机制。
				//获取指定对象上的排他锁
				System.Threading.Monitor.Enter(monitorLock); //加锁防止多线程创建单例
															 //如果另一个线程的对象已执行了Enter但尚未执行相应Exit,当前线程会阻塞,直到另一个线程释放对象。
				try {
					if (singleton == null) {
						//创建单例的实例
						//使用无参数构造函数创建由指定泛型类型参数指定的类型的实例。
						singleton = ((default(T) == null) ? Activator.CreateInstance<T>() : default);
					}
				}
				finally {
					//释放指定对象上的排他锁
					System.Threading.Monitor.Exit(monitorLock);
				}
			}
			return singleton;
		}
	}

	public static T Init() {
		return Instance;
	}
}

简单UI框架

  • UIFroms:存储所有UIFormd的路径信息,用于从Resources中动态加载。
  • UIType:存储UIPrefab的路径和名字
  • BaseView:定义UI的各种行为,OnOpen,OnPause,OnResume,OnExit
  • UIManager:UI框架的主要逻辑,创建和销毁UI

框架使用方法:

  1. 创建GameRoot脚本,在Awake()或Start()中调用:
		//初始化UIManager单例
		UIManager.Init();
		//创建第一个界面
		UIManager.Instance.OpenUI(UIFroms.panel_1);
  1. 创建UIFroms中的界面的预制体,并创建相应的XXXView脚本,继承BaseView,即可在其中重写BaseView的方法
public class PanelView : BaseView
{
	//将此方法绑定在该界面的按钮上
	public void OpenPlane2() {
		UIManager.Instance.OpenUI(UIFroms.panel_2);
	}
}

代码

UIType.cs
public class UIType {
	/// <summary>
	/// 每个字段,都有两个权限:读和写
	/// </summary>
	public string Path { get; set; }

	public string Name { get; private set; }

	public UIType(string _Path) {
		Path = _Path;
		Name = Path.Substring(Path.LastIndexOf('/') + 1);
	}
}
UIFroms.cs
/// <summary>
/// 这个脚本中,存放了所有UIForm的路径信息,是一个数据类
/// 
/// 当我创建了一个Panel,就把这个panel的路径信息写进来
/// 
/// </summary>
public class UIFroms {
	//static 为了方便调用。 readonly为了防止数据被修改
	public static readonly UIType panel_1 = new UIType("UIPrefabs/Panel1");
	public static readonly UIType panel_2 = new UIType("UIPrefabs/Panel2");
}
BaseView.cs
using UnityEngine;

public class BaseView : MonoBehaviour {

	public UIType Type {
		get;
		private set;
	}


	/// <summary>
	/// 被打开时:生成后,入栈时调用
	/// </summary>
	public virtual void OnOpen(UIType _type) {
		Type = _type;

	}

	/// <summary>
	/// 被暂停:当有新的UI入栈时,被调用
	/// </summary>
	public virtual void OnPause() {
		CanvasGroup cg = gameObject.GetComponent<CanvasGroup>();
		if (cg==null) {
			cg.gameObject.AddComponent<CanvasGroup>();
		}
		cg.blocksRaycasts = false;
	}

	/// <summary>
	/// 重新被激活:当上层UI出栈时,被调用
	/// </summary>
	public virtual void OnResume() {
		CanvasGroup cg = gameObject.GetComponent<CanvasGroup>();
		if (cg == null) {
			cg.gameObject.AddComponent<CanvasGroup>();
		}
		cg.blocksRaycasts = true;
	}

	/// <summary>
	/// 当被销毁时:出栈时调用
	/// </summary>
	public virtual void OnExit() {
		Destroy(gameObject);
	}
}
UIManager.cs
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 存放UI框架的逻辑
/// </summary>
public class UIManager:Singleton<UIManager> {



	/// <summary>
	/// 生成的UI对象
	/// </summary>
	public Stack<BaseView> uiViewsStack = new Stack<BaseView>();

	/// <summary>
	/// 所有生成的UI物体
	/// </summary>
	public Dictionary<UIType, GameObject> allUIFormsDic = new Dictionary<UIType, GameObject>();

	private Transform canvas = null;

	public UIManager() {
		if (canvas == null) {
			canvas = GameObject.Find("Canvas").transform;
		}
	}
	/// <summary>
	/// 打开一个UI,入栈
	/// 伪代码:算法描述
	/// 如果栈中没有元素,那么调用自己的OnOpen
	/// 如果已经已经有了元素,先调用上一个元素的OnPause,再调用这个的OnOpen
	/// 入栈
	/// 
	/// </summary>
	public void OpenUI(UIType uiType) {
		BaseView thisView = GetUI(uiType);
		if (uiViewsStack.Count != 0) {
			uiViewsStack.Peek().OnPause();
		}
		thisView.OnOpen(uiType);
		uiViewsStack.Push(thisView);

		/*GB
		if (uiViewsStack.Count==0) {
			thisView.OnOpen(uiType);
			uiViewsStack.Push(thisView);
			return;
		}
		BaseView lastView = uiViewsStack.Peek();
		lastView.OnPause();
		thisView.OnOpen(uiType);
		uiViewsStack.Push(thisView);
		*/
	}

	/// <summary>
	/// 销毁一个UI,出栈
	/// 做一个安全性判断:
	/// 先判断,栈中是否有元素,没有,直接返回,不做操作
	/// 有元素,从栈中移除,执行OnExit(),销毁这个物体
	/// 判断栈中是否还有元素
	/// 如果没有,跳过
	/// 如果有,渠道栈顶元素,执行OnResume()
	/// </summary>
	public void CloseUI() {
		if (uiViewsStack.Count != 0) {
			BaseView firstView = uiViewsStack.Pop();
			firstView.OnExit();
			DestroyUI(firstView.Type); //销毁栈顶元素

		}
		if (uiViewsStack.Count != 0) {
			BaseView secondView = uiViewsStack.Peek();
			secondView.OnResume();
		}

		/*GB
		if (uiViewsStack.Count == 0) {
			return;
		}
		BaseView firstView = uiViewsStack.Pop();//要销毁的栈顶元素
		firstView.OnExit();
		DestroyUI(firstView.Type); //销毁栈顶元素
		if (uiViewsStack.Count == 0) {
			return;
		}
		BaseView secondView = uiViewsStack.Peek();
		secondView.OnResume();
		*/
	}

	/// <summary>
	/// 获取一个UI
	/// 从字典中检测这个类型的UI是否存在
	/// 如果不存在,生成一个新的,返回,并把这个UI存到字典中
	/// 如果存在,直接返回
	/// </summary>
	/// <param name="uiType"></param>
	/// <returns></returns>
	public BaseView GetUI(UIType uiType) {
		//不存在
		if (allUIFormsDic.ContainsKey(uiType) == false || allUIFormsDic[uiType] == null) {
			GameObject go = GameObject.Instantiate(Resources.Load<GameObject>(uiType.Path), canvas);
			go.transform.localScale = Vector3.one*0.5f;
			allUIFormsDic[uiType]=go;
			return go.GetComponent<BaseView>();
		}
		return allUIFormsDic[uiType].GetComponent<BaseView>();
	}


	/// <summary>
	/// 从字典中删除UI
	/// </summary>
	public void DestroyUI(UIType type) {
		if (allUIFormsDic.ContainsKey(type)) {
			if (allUIFormsDic[type] != null) {
				GameObject.Destroy(allUIFormsDic[type].gameObject);
			}
			//从字典中删除
			allUIFormsDic.Remove(type);
			return;
		}

	}
}

使用

  1. 挂在在空物体上
    GameRoot.cs
using UnityEngine;

public class GameRoot : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
		Init();
    }

	public void Init() {
		UIManager.Init();
		UIManager.Instance.OpenUI(UIFroms.panel_1);
	}
}
  1. 挂在在界面预制物上
    PanelView.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PanelView : BaseView {
	public void OpenPlane1() {
		UIManager.Instance.OpenUI(UIFroms.panel_1);
	}
}
  1. Panel预制物需添加Canvas Group组件
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值