本文基于

https://github.com/chiuan/TTUIFramework

https://github.com/jarjin/LuaFramework_UGUI

进行的二次开发,Thanks!

需求:

1.需要一个UI面板管理器,逻辑写在lua里面,方便热更新。

2.管理器控制面板的打开(show),隐藏(Hide),销毁(Destroy),刷新(Rest)。

3.要有类似网页浏览器那样,点击后退(<---),会显示上一个页面。用到数据结构:栈(Stack),先进后出。打开顺序是线性的,点击“后退“”会线性的回退到上一层。

5.顶部固定的“后退”按钮所在面板,在上一层没的退的情况下,会Hide。

6.面板第一次打开是Instantiate,关闭是Hide,再次打开是Rest。避免频繁的 Instantiate和Destroy。我的想法是所有面板都是在切场景的时候,才全部Destroy。回收内存。

先看结果,不知道能不能吸引你继续往下看!

XPage:

 using System;
using UnityEngine;
using System.Collections;
using Object = UnityEngine.Object;
using LuaFramework; public enum EPageType
{
None,
Normal,
PopUp,
Fixed,
Toppest,
} public enum EPageMode
{
DoNothing,
HideOtherOnly,
HideOtherAndNeedBack,
} public enum EPageState
{
NONE,
OPEN, //打开
HIDE, //隐藏
CLOSE,//销毁
} public class XPageLoadBind
{
/// <summary>
/// 绑定你自己的资源加载管理器
/// </summary>
/// <param name="xPage"></param>
public static void Bind(XPage xPage)
{
xPage.delegateSyncLoadUI = Resources.Load;
//xPage.delegateAsyncLoadUI = ResourcesMgr.Load;
}
} public class XPage
{
public string m_pageName;
public string m_loadPath;
public GameObject m_pageInst;
public Transform m_pageTrans;
public EPageType m_pageType = EPageType.None;
public EPageMode m_pageMode = EPageMode.DoNothing;
public EPageState m_currState = EPageState.NONE; private string m_luaPageCtrl;
private string m_luaPageView; //delegate load ui function.
public Func<string, Object> delegateSyncLoadUI = null;
public Action<string, Action<Object>> delegateAsyncLoadUI = null; public XPage(string pageName, string loadPath)
{
m_pageName = pageName;
m_loadPath = loadPath;
} public void Awake()
{
m_luaPageCtrl = m_pageName + "Ctrl";
m_luaPageView = m_pageName + "View";
//Debug.LogError("call lua awake :(" + m_pageName + "Ctrl)");
Util.CallMethod(m_luaPageCtrl, "Awake",this); //设置type和mode
//m_pageType = EPageType.PopUp;
//m_pageMode = EPageMode.HideOtherAndNeedBack;
} public void Start()
{
m_currState = EPageState.OPEN;
m_pageInst.gameObject.SetActive(true);
AnchorUIGameObject();
//Debug.LogError("call lua start :(" + m_pageName + "Ctrl)");
Util.CallMethod(m_luaPageView, "Start", this.m_pageInst);
Util.CallMethod(m_luaPageCtrl, "Start");
} public void Rest()
{
m_currState = EPageState.OPEN;
m_pageInst.gameObject.SetActive(true);
//Debug.LogError("call lua rest :(" + m_pageName + "Ctrl)");
Util.CallMethod(m_luaPageCtrl, "Rest");
} public void Hide()
{
m_currState = EPageState.HIDE;
m_pageInst.gameObject.SetActive(false);
//Debug.LogError("call lua hide :(" + m_pageName + "Ctrl)");
Util.CallMethod(m_luaPageCtrl, "Hide");
} public void Destroy()
{
m_currState = EPageState.CLOSE;
GameObject.Destroy(m_pageInst);
//Debug.LogError("call lua destroy :(" + m_pageName + "Ctrl)");
Util.CallMethod(m_luaPageCtrl, "Destroy");
} public void LoadSync(Action<GameObject> callback)
{
if (this.m_pageInst == null && string.IsNullOrEmpty(m_loadPath) == false)
{
GameObject go = null;
if (delegateSyncLoadUI != null)
{
Object o = delegateSyncLoadUI(m_loadPath);
go = o != null ? GameObject.Instantiate(o) as GameObject : null;
}
else
{
go = GameObject.Instantiate(Resources.Load(m_loadPath)) as GameObject;
} if (go == null)
{
Debug.LogError("[UI] Cant sync load your ui prefab.");
return;
} m_pageInst = go;
m_pageTrans = go.transform; if (callback != null)
callback(go);
}
else
{
if (callback != null)
callback(m_pageInst);
}
} public void LoadAsync(Action<GameObject> callback)
{
XPageRoot.Instance.StartCoroutine(AsyncShow(callback));
} IEnumerator AsyncShow(Action<GameObject> callback)
{
if (this.m_pageInst == null && string.IsNullOrEmpty(m_loadPath) == false)
{
GameObject go = null;
bool _loading = true;
delegateAsyncLoadUI(m_loadPath, (o) =>
{
go = o != null ? GameObject.Instantiate(o) as GameObject : null; _loading = false; m_pageInst = go;
m_pageTrans = go.transform; if (callback != null)
callback(go);
}); float _t0 = Time.realtimeSinceStartup;
while (_loading)
{
if (Time.realtimeSinceStartup - _t0 >= 10.0f)
{
Debug.LogError("[UI] WTF async load your ui prefab timeout!");
yield break;
}
yield return null;
}
}
else
{
if (callback != null)
callback(m_pageInst);
}
} protected void AnchorUIGameObject()
{
if (XPageRoot.Instance == null || m_pageInst == null)
return; GameObject ui = m_pageInst; //check if this is ugui or (ngui)?
Vector3 anchorPos = Vector3.zero;
Vector2 sizeDel = Vector2.zero;
Vector3 scale = Vector3.one;
if (ui.GetComponent<RectTransform>() != null)
{
anchorPos = ui.GetComponent<RectTransform>().anchoredPosition;
sizeDel = ui.GetComponent<RectTransform>().sizeDelta;
scale = ui.GetComponent<RectTransform>().localScale;
}
else
{
anchorPos = ui.transform.localPosition;
scale = ui.transform.localScale;
} EPageType type = this.m_pageType;
if (type == EPageType.Normal)
{
ui.transform.SetParent(XPageRoot.Instance.normalRoot);
}
else if(type == EPageType.PopUp)
{
ui.transform.SetParent(XPageRoot.Instance.popupRoot);
}
else if (type == EPageType.Fixed)
{
ui.transform.SetParent(XPageRoot.Instance.fixedRoot);
}
else if (type == EPageType.Toppest)
{
ui.transform.SetParent(XPageRoot.Instance.ToppestRoot);
} if (ui.GetComponent<RectTransform>() != null)
{
ui.GetComponent<RectTransform>().anchoredPosition = anchorPos;
ui.GetComponent<RectTransform>().sizeDelta = sizeDel;
ui.GetComponent<RectTransform>().localScale = scale;
}
else
{
ui.transform.localPosition = anchorPos;
ui.transform.localScale = scale;
}
}
}

XpageMgr:

 using UnityEngine;
using System.Collections.Generic;
using System; public class XPageMgr
{
private static XPageMgr m_inst;
public static XPageMgr Inst
{
get
{
if (m_inst == null)
m_inst = new XPageMgr();
return m_inst;
}
} public XPage currShowXPage;//当前正打开的界面
public Stack<XPage> m_pageNeedBackPool = new Stack<XPage>();//需要返回的页面的池子,栈,先进后出
public Dictionary<string, XPage> m_pageDic = new Dictionary<string, XPage>();//所有的页面 public int GetNeedBackCount()
{
return m_pageNeedBackPool.Count;
} /// <summary>
/// 获取所有面板
/// </summary>
/// <returns></returns>
private List<XPage> GetAllPages()
{
return new List<XPage>(m_pageDic.Values);
} /// <summary>
/// 检查面板打开类型
/// </summary>
/// <param name="currXPage"></param>
private void CheckPageMode(XPage currXPage)
{
if (currXPage.m_pageMode == EPageMode.DoNothing)
{ }
else if (currXPage.m_pageMode == EPageMode.HideOtherOnly)
{
HideOtherPages(currXPage);
}
else if (currXPage.m_pageMode == EPageMode.HideOtherAndNeedBack)
{
HideOtherPages(currXPage);
m_pageNeedBackPool.Push(currXPage);
}
} private void HideOtherPages(XPage currXPage)
{
List<XPage> xpages = GetAllPages();
int count = xpages.Count;
for (int i = ; i < count; i++)
{
XPage curr = xpages[i];
if (curr.Equals(currXPage))
continue;
if (curr.m_currState == EPageState.OPEN && curr.m_pageType != EPageType.Fixed && curr.m_pageType != EPageType.Normal )
{
curr.Hide();
}
}
} /// <summary>
/// 检测面板是否在队列里
/// </summary>
/// <param name="pageName"></param>
/// <returns></returns>
private bool CheckPageExist(string pageName)
{
if (m_pageDic.ContainsKey(pageName))
{
return true;
}
else
{
return false;
}
} /// <summary>
/// 用相对路径获取面板名称
/// </summary>
/// <param name="pageLoadPath"></param>
/// <returns></returns>
private string GetPageName(string pageLoadPath)
{
string pageName = pageLoadPath.Substring(pageLoadPath.LastIndexOf("/") + );
return pageName;
} #region api
/// <summary>
/// 打开面板
/// </summary>
/// <param name="isSync">是否同步加载</param>
/// <param name="pageLoadPath">加载的相对路径</param>
public void ShowPage(bool isSync, string pageLoadPath)
{
string pageName = GetPageName(pageLoadPath);
bool isExist = CheckPageExist(pageName);
XPage currXPage = null;
if (isExist)
{
currXPage = m_pageDic[pageName];
if(currXPage.m_currState == EPageState.HIDE)
{
CheckPageMode(currXPage);
currXPage.Rest();
currShowXPage = currXPage;
}
}
else
{
//add
currXPage = new XPage(pageName, pageLoadPath);
currXPage.Awake();
XPageLoadBind.Bind(currXPage);
if (isSync)
{
currXPage.LoadSync((go) =>
{
m_pageDic.Add(pageName, currXPage);
currShowXPage = currXPage;
CheckPageMode(currXPage);
currXPage.Start(); });
}
else
{
currXPage.LoadAsync((go) =>
{
m_pageDic.Add(pageName, currXPage);
currShowXPage = currXPage;
CheckPageMode(currXPage);
currXPage.Start();
});
}
}
} /// <summary>
/// 隐藏当前的页面
/// </summary>
public bool HideCurrPage()
{
if (currShowXPage != null)
{
if (currShowXPage.m_pageMode == EPageMode.HideOtherAndNeedBack)
{
if (m_pageNeedBackPool.Count > )
{
if (m_pageNeedBackPool.Peek().Equals(currShowXPage))
{
XPage topPage = m_pageNeedBackPool.Pop();
topPage.Hide();
currShowXPage = null; if (m_pageNeedBackPool.Count > )
{
XPage _curr = m_pageNeedBackPool.Peek();
_curr.Rest();
currShowXPage = _curr;
}
}
}
}
else
{
if (currShowXPage.m_currState == EPageState.OPEN)
{
currShowXPage.Hide();
currShowXPage = null;
}
} return true;
}
else
{
Debug.Log("currShowPage is null");
return false;
}
} /// <summary>
///隐藏指定面板
/// </summary>
/// <param name="pageName">Page name.</param>
public void HidePage(string pageName)
{
bool isExist = CheckPageExist(pageName);
if (isExist)
{
XPage _currXpage = m_pageDic[pageName];
if(_currXpage.m_currState == EPageState.OPEN)
_currXpage.Hide();
} } /// <summary>
/// 销毁所有面板
/// </summary>
public void CloseAllPages()
{
List<XPage> allPages = GetAllPages();
int count = allPages.Count;
for (int i = ; i < count; i++)
{
allPages[i].Destroy();
allPages[i] = null;
}
m_pageDic.Clear();
m_pageNeedBackPool.Clear();
}
#endregion /// <summary>
/// 销毁
/// </summary>
public void Destroy()
{
CloseAllPages();
currShowXPage = null;
m_pageDic = null;
m_pageNeedBackPool = null;
m_inst = null;
Debug.Log("~XPageMgr was destroy");
}
}

XPageRoot:

 using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems; /// <summary>
/// Init The UI Root
/// </summary>
public class XPageRoot : MonoBehaviour
{
private static XPageRoot m_Instance = null;
public static XPageRoot Instance
{
get
{
if (m_Instance == null)
{
InitRoot();
}
return m_Instance;
}
} public Transform root;
public Transform normalRoot;//Canvas order in layer 0
public Transform popupRoot;//
public Transform fixedRoot;//
public Transform ToppestRoot;//
public Camera uiCamera; static void InitRoot()
{
GameObject go = new GameObject("UIRoot");
go.layer = LayerMask.NameToLayer("UI");
m_Instance = go.AddComponent<XPageRoot>();
go.AddComponent<RectTransform>();
m_Instance.root = go.transform; Canvas can = go.AddComponent<Canvas>();
can.renderMode = RenderMode.ScreenSpaceCamera;
can.pixelPerfect = true;
GameObject camObj = new GameObject("UICamera");
camObj.layer = LayerMask.NameToLayer("UI");
camObj.transform.parent = go.transform;
camObj.transform.localPosition = new Vector3(, , -100f);
Camera cam = camObj.AddComponent<Camera>();
cam.clearFlags = CameraClearFlags.Depth;
cam.orthographic = true;
cam.farClipPlane = 200f;
can.worldCamera = cam;
m_Instance.uiCamera = cam;
cam.cullingMask = << ;
cam.nearClipPlane = -50f;
cam.farClipPlane = 50f; //add audio listener
camObj.AddComponent<AudioListener>();
camObj.AddComponent<GUILayer>(); CanvasScaler cs = go.AddComponent<CanvasScaler>();
cs.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
cs.referenceResolution = new Vector2(1136f, 640f);
cs.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand; ////add auto scale camera fix size.
//TTCameraScaler tcs = go.AddComponent<TTCameraScaler>();
//tcs.scaler = cs; //set the raycaster
//GraphicRaycaster gr = go.AddComponent<GraphicRaycaster>(); GameObject subRoot = CreateSubCanvasForRoot(go.transform, );
subRoot.name = "NormalRoot";
m_Instance.normalRoot = subRoot.transform; subRoot = CreateSubCanvasForRoot(go.transform, );
subRoot.name = "PopupRoot";
m_Instance.popupRoot = subRoot.transform; subRoot = CreateSubCanvasForRoot(go.transform, );
subRoot.name = "FixedRoot";
m_Instance.fixedRoot = subRoot.transform; subRoot = CreateSubCanvasForRoot(go.transform, );
subRoot.name = "ToppestRoot";
m_Instance.ToppestRoot = subRoot.transform; //add Event System
GameObject esObj = GameObject.Find("EventSystem");
if (esObj != null)
{
GameObject.DestroyImmediate(esObj);
} GameObject eventObj = new GameObject("EventSystem");
eventObj.layer = LayerMask.NameToLayer("UI");
eventObj.transform.SetParent(go.transform);
eventObj.AddComponent<EventSystem>();
if (!Application.isMobilePlatform || Application.isEditor)
{
eventObj.AddComponent<UnityEngine.EventSystems.StandaloneInputModule>();
}
else
{
eventObj.AddComponent<UnityEngine.EventSystems.TouchInputModule>();
} } static GameObject CreateSubCanvasForRoot(Transform root, int sort)
{
GameObject go = new GameObject("canvas");
go.transform.parent = root;
go.layer = LayerMask.NameToLayer("UI"); Canvas can = go.AddComponent<Canvas>();
RectTransform rect = go.GetComponent<RectTransform>();
rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, , );
rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, , );
rect.anchorMin = Vector2.zero;
rect.anchorMax = Vector2.one; can.overrideSorting = true;
can.sortingOrder = sort; go.AddComponent<GraphicRaycaster>(); return go;
} void OnDestroy()
{
m_Instance = null;
}
}

ToLua使用:

熟悉Tolua的同学都知道要

_GT(typeof(XPage)),
_GT(typeof(XPageMgr)),
_GT(typeof(EPageType)),
_GT(typeof(EPageMode)),
_GT(typeof(EventTriggerListener)),

如果你还不知道ToLua是什么,那么你先去了解一下咯。

这样,这些类,在lua里就能用了。

初始化:

 require "Logic/LuaClass"
require "Common/define"
require "Common/functions" --管理器--
XGame = {};
local this = XGame; local game;
local transform;
local gameObject;
local WWW = UnityEngine.WWW; function XGame.InitViewPanels()
for i = , #XPanelNames do
require ("XUI/XView/"..tostring(XPanelNames[i]).."View")
require ("XUI/XCtrl/"..tostring(XPanelNames[i]).."Ctrl")
end
end xpageMgr = XPageMgr.Inst --初始化完成,发送链接服务器信息--
function XGame.OnInitOK()
--注册LuaView--
this.InitViewPanels(); logWarn('LuaFramework InitOK--->>>');
end

当你调XPageMgr.Inst.ShowPage(true, "UI/UIPrefab/MainPanel");来显示MainPanel的面板时

我的做法是去调lua里面MainPanelCtrl,MainPanelView。

MainPanelCtrl

 local transform;
local gameObject; MainPanelCtrl = {};
local this = MainPanelCtrl; --构建函数--
function MainPanelCtrl.New()
logWarn("MainPanelCtrl.New--->>");
return this;
end function MainPanelCtrl.Awake(xpage)
--logWarn('MainPanelCtrl Awake--->>>'..'xpage name:'..xpage.m_pageName);
xpage.m_pageType = EPageType.Normal;
xpage.m_pageMode = EPageMode.DoNothing;
end function MainPanelCtrl.Start()
logWarn('MainPanelCtrl Start--->>>');
local eventTriggerListener = EventTriggerListener.Get(MainPanelView.packageBtn.gameObject);
eventTriggerListener:AddClick(MainPanelView.packageBtn,this.OnClick);
end function MainPanelCtrl.Rest()
logWarn('MainPanelCtrl Rest--->>>');
end function MainPanelCtrl.Hide()
logWarn('MainPanelCtrl Hide--->>>');
end function MainPanelCtrl.Destroy()
logWarn('MainPanelCtrl Destroy--->>>');
end --单击事件--
function MainPanelCtrl.OnClick(go)
xpageMgr:ShowPage(true,"UI/UIPrefab/TopBar");
xpageMgr:ShowPage(true,"UI/Prompt/PromptPanel");
end

MainPanelView

 local transform;
local gameObject; MainPanelView = {};
local this = MainPanelView; function MainPanelView.Start(obj)
gameObject = obj;
transform = obj.transform;
logWarn('MainPanelView Start--->>>'..gameObject.name); this.packageBtn = transform:FindChild("Button").gameObject;
end

其他面板也是这个道理,所以我的结构是这样的。

结束语:

1.代码写的很粗糙,但是基本满足我目前的需求。

2.再次感谢开源,避免重复造轮子,毕竟人生苦短,当你有想法时,也许可以进行二次开发。

Unity3d:UI面板管理整合进ToLua的更多相关文章

  1. hibernate整合进spring后的事务处理

    单独使用hibernate处理事务 本来只用hibernate开发,从而可以省了DAO层实现数据库访问和跨数据库,也可以对代码进行更好的封装,当我们web中单独使用hibernate时,我们需要单独的 ...

  2. UI的管理

    游戏的UI系统往往会比较复杂,工作量比较庞大,需要多人协作完成,为了开发和维护方便,有必要对UI系统进行管理. 一.制作预制件 将UI的各个不同的功能面板制作为预制件,放入Resources目录下,方 ...

  3. iOS10 UI教程管理层次结构

    iOS10 UI教程管理层次结构 iOS10 UI教程管理层次结构,在一个应用程序中,如果存在多个层次结构,就需要对这些层次结构进行管理.在UIView类中提供了可以用来管理层次结构的方法,让开发者可 ...

  4. Daikon Forge GUI 制作UI面板

    因为是第一次写技术博客,文章的结构和层次估计不标准,但是并不妨碍我想表达的内容. DF-GUI知识 DF-GUI初窥 DF-GUI于今年10月份面世,作为为数不多的unity UI插件,其功能值得一窥 ...

  5. DZ升级到X3.2后,UCenter用户管理中心进不了了

    前天将DZ升级到X3.2后,UCenter用户管理中心进不了了,输入的密码也对,验证码也对,就是点登录后没反应,又回来输入前的状态.如果更换密码后,显示密码错误,证明密码是没错的.但就是进不了.大家看 ...

  6. JavaScript怎么把对象里的数据整合进另外一个数组里

    https://blog.csdn.net/qq_26222859/article/details/70331833 var json1 = [ {"guoshui":[ 3000 ...

  7. 宝塔面板管理阿里云服务器FTP不能用

    # 宝塔面板管理阿里云,ftp不能用 解决方法 搜ftp点击设置 然后Ctrl+F搜索ForcePassiveIP 注意2在默认情况下是带#号的,去掉#号,后面的ip地址是阿里云的公网ip 重启,再次 ...

  8. UI(UGUI)框架(二)-------------UIManager单例模式与开发BasePanel面板基类/UIManage统一管理UI面板的实例化/开发字典扩展类

    UIManage单实例: /// 单例模式的核心 /// 1,定义一个静态的对象 在外界访问 在内部构造 /// 2,构造方法私有化 private static UIManager _instanc ...

  9. Docker整合dockerfly实现UI界面管理(单机版)

    一.搜索镜像 docker search dockerfly 二.根据镜像使用排名(一般情况下拉取使用率最高的镜像名),我这里使用的是阿里云镜像地址 docker pull registry.cn-h ...

随机推荐

  1. 收藏的Android学习资源

    1. Android中混合开发系列 Android中Java与JavaScript的交互,可用来实现网页与本地APP的交互,信息的传递等: 谈谈App的混合开发,可以让一部分功能由html5开发,这部 ...

  2. Rails Array method second/third/second_to_last

    http://api.rubyonrails.org/classes/Array.html#method-i-second [27] pry(main)> list = ["a&quo ...

  3. sed命令详解

    搜索 纠正错误  添加实例 sed 功能强大的流式文本编辑器 补充说明 sed 是一种流编辑器,它是文本处理中非常中的工具,能够完美的配合正则表达式使用,功能不同凡响.处理时,把当前处理的行存储在临时 ...

  4. linux 下Qt WebEngine 程序打包简单记录

    本次记录仅作参考. 程序说明: 程序是一个编解码器控制管理的工具,使用到的库有:Qt的WebEngine.OpenGL模块.poco库.libmicrohttpd.libcurl.libvlc.同时程 ...

  5. 【sdoi2013】森林 BZOJ 3123

    Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负整数 ...

  6. Integer与int的区别

    简述:int与Integer的区别: 对于它们,我们可能只是知道简单的区别.Integer是int的一个封装类,int的初始值为0,而Integer的初始值为null.但是他们之间真的仅仅只有这些区别 ...

  7. B+Tree和MySQL索引分析

    首先区分两组概念: 稠密索引,稀疏索引: 聚簇索引,非聚簇索引: btree和mysql的分析: 参见 http://blog.csdn.net/hguisu/article/details/7786 ...

  8. c++ 陷阱

    .c89 c90 gnu90 c99 c11 c++98( default ) c++03 c++11 gnu++11 boolC 标准 does not support the boolean da ...

  9. C# Interface的使用方法探讨

    接口是把公共实例(非静态)的方法和属性结合起来,以封装特定功能的一个集合,一旦定义了接口,就可以在类中使用实现接口中的所有成员,接口可以看作创建者和使用者之间的契约,一旦实现了接口,就不要轻易变动(如 ...

  10. Xcode 常用快捷键

    一.Xcode基本快捷键 1.1.新建项目 Shift + CMD + N 1.2.项目中新建文件 CMD + N 1.3.运行 CMD + R 1.4.编译 CMD + B 1.5.停止运行 CMD ...