您的位置:首页 > 移动开发 > Unity3D

Unity3D快速实现UI架构设计一

2017-05-14 20:14 411 查看
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。CSDN视频网址:http://edu.csdn.net/lecturer/144 在利用Unity3D引擎开发程序时,UI资源的加载,卸载,隐藏以及UI渐变动画等功能是UI架构设计必须考虑的。做每一款游戏都需要将这些功能编写一遍非常耗时,在此给读者介绍一种快速的实现方式,因为我们这个是通用的模块,所以必须要使用模板实现,而且我们的逻辑脚本是不挂接到对象上的。接下来首先设计一个管理类Manager,代码如下所示:using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
/// <summary>
/// 抽象管理类
/// </summary>
/// <typeparam name="K"></typeparam>
/// <typeparam name="V"></typeparam>
public class Manager<T,K, V> : Singleton<T>
where V : class ,IDisposable
where T : Singleton<T>, new()
{
protected Dictionary<K, V> mMap = new Dictionary<K, V>();

/// <summary>
/// 获取 对应实体
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public V Get(K key)
{
if (key == null) return null;
return mMap.ContainsKey(key) ? mMap[key] : null;
}

/// <summary>
/// 获取类型T的 Value
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public U Get<U>(K key) where U : class,V
{
V v = Get(key);
return v as U;
}

/// <summary>
/// 获取类型T的Value
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Get<T>() where T : class,V
{
foreach(V value in mMap.Values)
{
if(value.GetType().Equals(typeof(T)))
{
return value as T;
}
}
return null;
}
/// <summary>
/// 添加对应实体
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public bool Put(K key, V value)
{
if (mMap.ContainsKey(key))
{
if (value == mMap[key])
{
return false;
}
V v = mMap[key];
mMap[key] = value;
v.Dispose();
}
else
{
mMap.Add(key, value);
}
return true;
}

/// <summary>
/// 删除
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool Remove(K key)
{
if (mMap.ContainsKey(key))
{
V v = mMap[key];
mMap.Remove(key);
v.Dispose();
}
return true;
}

public Dictionary<K,V>.ValueCollection Values
{
get { return mMap.Values; }
}
/// <summary>
/// 清除所有管理的对象
/// </summary>
public void Clear()
{
foreach (V value in mMap.Values)
{
value.Dispose();
}
mMap.Clear();
}
}

public class ManagerT<K, V> : Manager<ManagerT<K,V>, K, V>
where V : class ,IDisposable
{

}

在这个类属于抽象类,它利用Dictionary实现了对象的管理操作,接下来需要实现UI的管理类了,先把代码给读者展示如下:using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

/// <summary>
/// UI 服务类
/// </summary>
public class UIService : Manager<UIService, string, UIService.UI>,IDisposable
{
public void Dispose()
{
DestroyAll();
}

/// <summary>
/// 创建UI
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
private T _CreateUI<T>(string name) where T : UI
{
T ui = Activator.CreateInstance(typeof(T), name) as T;
return ui;
}

public class UIHolder : MonoBehaviour
{
public UI ui { get; set; }
}
public class UI : IDisposable
{
public UI(string name)
{
_Init(name);
}

public enum UIStyle
{
Normal,//默认类型
HideByTapScene,//点击空白处隐藏类型,和黑底不冲突
}

UIStyle mStyle = UIStyle.Normal;

public UIStyle Style
{
get { return mStyle; }
set { mStyle = value; }
}

internal GameObject mPrefab = null;
protected UIPanel mPanel = null;
#region 面板动画处理
protected UITweener[] mTweens = null;
protected UITweener mMainTween = null;
protected UITweener.ToggleStyle mMainToggleStyle = UITweener.ToggleStyle.normal;
private void _TweensInit()
{
mTweens = mPrefab.GetComponentsInChildren<UITweener>();
if (mTweens != null)
{
UITweener tween;
for (int i = 0; i < mTweens.Length; ++i)
{
tween = mTweens[i];
if (tween.toggleStyle == UITweener.ToggleStyle.OnShow)
{
mMainTween = tween;
mMainToggleStyle = UITweener.ToggleStyle.OnShow;
}
if (tween.toggleStyle == UITweener.ToggleStyle.OnShowAndHide)
{
mMainTween = tween;
mMainToggleStyle = UITweener.ToggleStyle.OnShowAndHide;
break;
}
}
}
}

private bool _HasTween()
{
return mMainTween != null && mMainTween.toggleStyle != UITweener.ToggleStyle.normal;
}
private void _TweenOnShow(EventDelegate.Callback call)
{
mMainTween.SetOnFinished(call);
UITweener tween;
for (int i = 0; i < mTweens.Length; ++i)
{
tween = mTweens[i];
if(tween.toggleStyle != UITweener.ToggleStyle.normal)
{
tween.ResetToStart(true);
tween.PlayForward();
}
}
}

private void _TweenOnHide(EventDelegate.Callback call)
{
if (mMainToggleStyle == UITweener.ToggleStyle.OnShow)
{
call();
return;
}
mMainTween.SetOnFinished(call);
UITweener tween;
for (int i = 0; i < mTweens.Length; ++i)
{
tween = mTweens[i];
if (tween.toggleStyle == UITweener.ToggleStyle.OnShowAndHide)
{
tween.ResetToStart(!true);
tween.PlayReverse();
}
}
}
private void _Dummy()
{

}
private void _Hide()
{
mPrefab.SetActive(false);
mHiding = false;
}
#endregion

internal void _Init(string name)
{
try
{
GameObject prefab = Resource.LoadUI(name);
mPrefab = GameObject.Instantiate(prefab) as GameObject;
UIHolder uiholder = UtilGameObject.GetOrAddComponent<UIHolder>(mPrefab);
uiholder.ui = this;
mPrefab.name = name;
mPanel = mPrefab.GetComponent<UIPanel>(); //允许Panel为空
_TweensInit();
}
catch (Exception e)
{
Looper.LogException(e);
}
UIService.Instance.InitUI(mPrefab);
UIService.Instance._OnShowUI(this, true);
}
#region <默认属性>

/// <summary>
/// 深度信息
/// </summary>
public int depth
{
get
{
if (mPanel==null)
{
return -1;
}
return mPanel.depth;
}
set
{
if (mPanel == null) return;
mPanel.depth = value;
}
}
/// <summary>
/// 是否正在显示
/// </summary>
/// <returns></returns>
public bool IsShowing()
{
if (mPrefab == null)
return false;
return mPrefab.activeSelf;
}
float mLastShowTime = Time.time;
/// <summary>
/// 最后一次显示的时间
/// </summary>
public float LastShowTime
{
get { return mLastShowTime; }
set { mLastShowTime = value; }
}
#endregion

/// <summary>
/// 名字(和预制件名称一样)
/// </summary>
public string Name
{
get { return mPrefab != null ? mPrefab.name : ""; }
}
/// <summary>
/// 销毁对象
/// </summary>
public void Dispose()
{
UIService.Instance._OnHidUI(this);

try
{
OnClose();
if (mPrefab != null)
{
GameObject.DestroyImmediate(mPrefab);
mPrefab = null;
}

}
catch (Exception e)
{
Looper.LogException(e);
}

}

/// <summary>
/// 刷新界面
/// 1 Grid 重排问题
/// </summary>
public void Refresh()
{

UIGrid[] grids = mPrefab.GetComponentsInChildren<UIGrid>();
foreach (UIGrid grid in grids)
{
if (grid != null && !grid.animateSmoothly)
{
grid.Reposition();
}
}

}

public IEnumerator _Refresh()
{
{
UIGrid[] grids = mPrefab.GetComponentsInChildren<UIGrid>();
foreach (UIGrid grid in grids)
{
if (grid != null && !grid.enabled)
{
grid.repositionNow = true;
grid.Reposition();
}
}
}

yield return null;
}

//解决同一个UI动画隐藏还没结束,动画显示就开始了 状态不对的问题
bool mHiding = false;
/// <summary>
/// 是否显示
/// </summary>
public void Show(bool v)
{

if (v)
{
if (mHiding)
{
_Hide();
}
UIService.Instance._OnShowUI(this);
}
else
{
UIService.Instance._OnHidUI(this);
}

try
{

if (mPrefab != null)
{

if (_HasTween())
{
if (v)
{
mPrefab.SetActive(true);
_TweenOnShow(_Dummy);
}
else
{
mHiding = true;
_TweenOnHide(_Hide);
}
}
else
{
mPrefab.SetActive(v);
}
OnShow(v);
if (v)
{
LastShowTime = Time.time;
Refresh();
//();
}
}

}
catch (Exception e)
{
Looper.LogException(e);
}

}

/// <summary>
/// 跟随场景中物体
/// </summary>
/// <param name="target"></param>
public void ApplyHub(Transform target)
{
NGUIExt guiExt = PluginManager.Instance.Get<NGUIExt>();
if (guiExt != null)
{
guiExt.ApplyHud(mPrefab, target);
}
}

public virtual void OnCreate() { }
public virtual void OnShow(bool v) { }
public virtual void OnClose() { }

/// <summary>
/// 点击事件
/// </summary>
/// <param name="obj">被点击的控件</param>
public virtual void OnClick(GameObject obj) { }

/// <summary>
/// 双击事件
/// </summary>
/// <param name="obj">被双击的控件</param>
public virtual void OnDoubleClick(GameObject obj) { }
/// <summary>
/// 按住事件
/// </summary>
/// <param name="obj">被Pressed的控件</param>
/// <param name="pressed"></param>
public virtual void OnPress(GameObject obj, bool isPressed) { }

/// <summary>
/// 拖动事件
/// </summary>
/// <param name="obj">拖动的控件</param>
/// <param name="delta"></param>
public virtual void OnDrag(GameObject obj, Vector2 delta) { }

/// <summary>
/// 拖放事件
/// </summary>
/// <param name="obj">拖放的当前控件</param>
/// <param name="objSelected">一直被拖住的控件</param>
public virtual void OnDrap(GameObject obj, GameObject objSelected) { }

/// <summary>
/// 显示Tooltip事件
/// </summary>
/// <param name="obj"></param>
/// <param name="isShow">显示或隐藏Tooltip</param>
public virtual void OnTooltip(GameObject obj, bool isShow) { }

/// <summary>
/// 被选中事件
/// </summary>
/// <param name="obj">被选中的控件</param>
/// <param name="isSelected">选中或取消被选中</param>
public virtual void OnSelect(GameObject obj, bool isSelected) { }

/// <summary>
/// 光标划过事件
/// </summary>
/// <param name="obj"></param>
/// <param name="isHover">光标进入或光标离开</param>
public virtual void OnHover(GameObject obj, bool isHover) { }

/// <summary>
/// 根据类型获取对应名称控件;
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
protected T GetChild<T>(string name,GameObject obj = null, int index = 0) where T : MonoBehaviour
{
if(obj == null)
{
obj = mPrefab;
}

Transform child = obj.transform.Find(name);
if (child == null)
{
T[] childs = obj.GetComponentsInChildren<T>();
foreach (T t in childs)
{
if (t.gameObject.name == name)
{
return t;
}
}
}
else
{
if (child.childCount == 0)
{
return child.GetComponent<T>();
}

{
int count = 0;
T[] comps = child.GetComponents<T>();
foreach (T t in comps)
{

if (t.gameObject.name == name && count == index)
{
return t;
}
count++;
}
}
{
int count = 0;
T[] childs = child.GetComponentsInChildren<T>();
foreach (T t in childs)
{

if (t.gameObject.name == name && count == index)
{
return t;
}
count++;
}
}

}

Debug.LogError(obj.name + " hasn't Components :" + typeof(T).Name + " in children named:" + name);
return null;
}

protected GameObject FindChild(string name)
{
var child = mPrefab.transform.FindChild(name);
return child.gameObject;
}

protected T FindChild<T>(string name) where T : Component
{
var child = mPrefab.transform.FindChild(name);
T cmp = child.GetComponent<T>();

return cmp;
}

/// <summary>
/// 获取对应名称子控件;
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
protected GameObject GetChild(string name, GameObject obj = null)
{
if(obj == null)
{
obj = mPrefab;
}
Transform child = obj.transform.Find(name);
if (child == null)
{
Debug.LogError(obj.name + "is not find child of:" + name);
return null;
}
return child.gameObject;
}
/// <summary>
/// 用指定的对象替换子对象
/// </summary>
/// <param name="name">子对象名字</param>
/// <param name="obj">指定的对象</param>
/// <returns></returns>
protected bool ReplaceChild(string name, GameObject obj)
{
GameObject orginal = GetChild(name);

if (orginal == null) {
GameObject.DestroyImmediate (obj);
return false;
}
obj.transform.parent = orginal.transform.parent;
obj.transform.localPosition = Vector3.zero;
obj.transform.localRotation = Quaternion.identity;
obj.transform.localScale = Vector3.one;
obj.name = orginal.name;

orginal.transform.parent = null;
GameObject.DestroyImmediate (orginal);

return true;
}

/// <summary>
/// 用指定的对象替换子对象
/// </summary>
/// <param name="orginal">原件</param>
/// <param name="obj">指定的对象</param>
/// <returns></returns>
protected bool ReplaceChild(GameObject orginal, GameObject obj)
{
if (orginal == null) {
GameObject.DestroyImmediate (obj);
return false;
}
obj.transform.parent = orginal.transform.parent;
obj.transform.localPosition = Vector3.zero;
obj.transform.localRotation = Quaternion.identity;
obj.transform.localScale = Vector3.one;
obj.name = orginal.name;

orginal.transform.parent = null;
GameObject.DestroyImmediate (orginal);
return true;
}

}

NGUIExt mPlugin;
GameObject mBG;
UIPanel mBGPanel;
int mBGCount = 0;

private void _OnShowUI(UI t,bool init = false)
{
if (t.IsShowing())
{
if(!init)
return;
}
if (t.IsShowBlackBG())
{
mBGCount++;
if (mBGCount > 0 && mBG.activeSelf == false)
{
mBG.SetActive(true);
}
if (mBG.activeSelf)
{
mBGPanel.depth = t.depth-1;
}
}

}
private void _OnHidUI(UI t)
{
if (!t.IsShowing()) return;

if (t.IsShowing() && t.IsShowBlackBG())
{
mBGCount--;
if(mBGCount <= 0)
{
mBGCount = 0;
if (mBG.activeSelf == true)
{
mBG.SetActive(false);
}
}

if (mBG.activeSelf)
{
UI ui = _GetLastShowUI(true, t);
if (ui != null) mBGPanel.depth = ui.depth-1;
}
}

}

public bool IsFingerHoverGUI()
{
if(mPlugin == null)
{
return false;
}
return mPlugin.IsFingerHoverGUI;
}

public bool IsFingerHoverGUI3D()
{
if (mPlugin == null)
{
return false;
}
return mPlugin.IsFingerHoverGUI3D();
}

public bool IsFingerHoverGUIWithout3D()
{
if (mPlugin == null)
{
return false;
}
return mPlugin.IsFingerHoverGUIWithout3D();
}

public bool IsPrefab(GameObject ui_prefab)
{
return mPlugin.IsPrefab(ui_prefab);
}

/// <summary>
/// 初始化 继承与 Singleton 对象构建的时候被调用
/// </summary>
protected override void OnCreate()
{

mPlugin = PluginManager.Instance.Get<NGUIExt>();
if (mPlugin != null)
{
mPlugin.SetEventHandler(this._HandlerUIEvent);
}
GameObject prefab = Resource.LoadUICommon("black_background");
Looper.Assert(prefab != null , "默认黑底 black_background Prefab不存在 !!");
if(prefab != null)
{
mBG = mPlugin.AddChild(prefab);
mBGPanel = mBG.GetComponent<UIPanel>();
mBG.transform.localScale = new Vector3(1, 1, 1);
mBG.transform.localPosition = new Vector3(mBG.transform.localPosition.x, mBG.transform.localPosition.y, Mathf.Clamp(mBG.transform.localPosition.z, -2f, 2f));
if(mBG != null)
{
UISprite sprite = mBG.GetComponent<UISprite>();
BoxCollider collider = mBG.GetComponent<BoxCollider>();
if(sprite!= null)
{
Vector2 size = mPlugin.GetSize();
sprite.SetDimensions((int)size.x, (int)size.y);
collider.size = new Vector3(size.x, size.y, 0);
}
}

mBG.SetActive(false);
}
//EasyTouch.On_SimpleTap += On_SimpleTap;

}

public void InitUI(GameObject ui)
{
try
{
LayerUtils.SetLayer(ui.transform, (int)LayerUtils.ELayerIndex.ui);
ui.transform.parent = mPlugin.GetRoot().transform;

switch(ui.name)
{
default:
ui.transform.localScale = new Vector3(1, 1, 1);
ui.transform.localPosition = Vector3.zero;
break;
}
}
catch (Exception e)
{
Looper.LogException(e);
}

}
/// <summary>
/// 创建UI
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
public T CreateUI<T>(string name) where T: UI
{
UI t = this.Get(name) as T;
if(t == null)
{
t = _CreateUI<T>(name) as UI;
try
{
t.OnCreate();
}
catch (Exception e)
{
Looper.LogException(e);
}

Put(name, t);
}
return t as T;
}
List<UI> mUIScene = new List<UI>();
/// <summary>
/// 创建一个不加入管理队列的UI,主要用于世界地图上关卡界面的创建。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
public T CreateUIWithoutManager<T>(string name) where T : UI
{
T ui = _CreateUI<T>(name);
try
{
ui.OnCreate();
}
catch (Exception e)
{
Looper.LogException(e);
}
mUIScene.Add(ui);
return ui;
}

/// <summary>
/// 销毁不加入队列的UI
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ui"></param>
public void CloseUIWithoutManager<T>(T ui) where T : UI
{
try
{
ui.OnClose();
ui.Dispose();
}
catch (Exception e)
{
Looper.LogException(e);
}
mUIScene.Remove(ui);
}
/// <summary>
/// 显示UI
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
public T ShowUI<T>(string name) where T : UI
{
T t = CreateUI<T>(name);
if(t != null)
{
t.Show(true);
}
return t;
}
/// <summary>
/// 显示UI
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
public T HideUI<T>(string name) where T : UI
{
T t = Get<T>(name);
if (t != null)
{
t.Show(!true);

}
return t;
}

Stack<UI> mStack = new Stack<UI>();

/// <summary>
/// 清除栈
/// </summary>
public void StackClean()
{
mStack.Clear();
}
/// <summary>
/// UI隐藏压栈
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public UI Push(UI t)
{
if (t != null)
{
t.Show(false);
mStack.Push(t);
}
return t;
}
/// <summary>
/// UI隐藏压栈
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public T Push<T>(string name) where T: UI
{
T t = Get<T>(name);
if (t != null)
{
t.Show(false);
mStack.Push(t);
}
return t;
}
/// <summary>
/// UI显示出栈
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public UI Pop()
{
UI t = mStack.Pop();
if (t != null)
{
t.Show(true);
}
return t;
}

/// <summary>
/// 销毁UI
/// </summary>
/// <param name="name"></param>
public void Distroy(string name)
{
UI ui = Get(name);
if(ui != null)
{
ui.Dispose();
Remove(name);
}
}

public void Distroy<T>(string name) where T : UI
{
UI ui = Get<T>(name);
if (ui != null)
{
ui.Dispose();
Remove(name);
}
}
public void DestroyAll(bool includeScene= false)
{
StackClean();
Clear();
if(includeScene)
{
foreach (UI ui in mUIScene)
{
ui.Dispose();
}
mUIScene.Clear();
}

}
/// <summary>
/// 隐藏其他UI
/// </summary>
/// <param name="name"></param>
public void HideOtherUI(string name)
{
foreach (UI ui in Values)
{
if (ui.Name.Equals(name))
continue;
ui.Show(false);
}
}

UI _GetLastShowUI(bool showBG = false,UI except=null)
{
UI lastShowUI = null;
float lastShowTime = 0;
foreach (UI ui in Values)
{
if (ui == except) continue;
if (ui.IsShowing() && ui.LastShowTime > lastShowTime)
{
if (showBG)
{
if (ui.IsShowBlackBG())
{
lastShowUI = ui;
lastShowTime = ui.LastShowTime;
}
}else
{
lastShowUI = ui;
lastShowTime = ui.LastShowTime;
}
}
}
return lastShowUI;
}

/// <summary>
/// 隐藏最新显示的UI
/// </summary>
public void HideLastShow()
{
UI lastShowUI = _GetLastShowUI();
if (lastShowUI != null)
{
lastShowUI.Show(false);
}
}
/// <summary>
/// 隐藏所有UI
/// </summary>
public void HideAllUI()
{
foreach(UI ui in Values)
{
if(ui != null)ui.Show(false);
}
}
/// <summary>
/// 获取UI跟面板
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
GameObject _GetRootPanelExt(GameObject obj)
{
Transform parent = obj.transform.parent;
UIHolder uiHolder = null;// = root.GetComponent<UIService.UIHolder>();

while (parent != null)
{
if (parent.gameObject.GetComponent<UICamera>() != null)
break;

UIHolder tempPanel = parent.GetComponent<UIHolder>();
if (tempPanel != null)
{
uiHolder = tempPanel;
}
parent = parent.parent;
}
if (uiHolder == null)
{
return null;
}
return uiHolder.gameObject;
}
/// <summary>
/// NGUI事件处理器
/// </summary>
/// <param name="eventNane">事件名称</param>
/// <param name="sender">发送事件的控件</param>
/// <param name="arg">事件参数</param>
private void _HandlerUIEvent(string eventName, GameObject sender, object arg)
{
try
{
if(sender == mBG)
{
//MainLooper.LogError("mBG, eventName:" + eventName + "!!");
if (eventName.Equals("OnClick"))
{

}
return;
}
GameObject root = _GetRootPanelExt(sender);//mPlugin.GetRootPanel(sender);
if (root == null) return;
UI ui = Get(root.name);
if(ui == null)
{
UIHolder uiHolder = root.GetComponent<UIHolder>();
if( uiHolder!= null) ui = uiHolder.ui;
}
if (ui == null)
{
Debug.LogWarning("UI:" + root.name + " not match prefab's name " + sender.name);
return;
}

if (eventName.Equals("OnClick"))
{
ui.OnClick(sender);
}
else if (eventName.Equals("OnPress"))
{
ui.OnPress(sender, (bool)arg);
}
else if (eventName.Equals("OnDrag"))
{
ui.OnDrag(sender, (Vector2)arg);
}
else if (eventName.Equals("OnDrop"))
{
ui.OnDrap(sender, (GameObject)arg);
}
else if (eventName.Equals("OnSelect"))
{
ui.OnSelect(sender, (bool)arg);
}
else if (eventName.Equals("OnHover"))
{
ui.OnHover(sender, (bool)arg);
}
else if (eventName.Equals("OnTooltip"))
{
ui.OnTooltip(sender, (bool)arg);
}
else if (eventName.Equals("OnDoubleClick"))
{
ui.OnDoubleClick(sender);
}
}
catch(Exception e)
{
Looper.LogException(e);
}

}
}

该类实现了UI的创建,也就是我们说的实例化操作,以及UI的显示,隐藏,动画等效果。在代码的最后使用了点击的回调函数避免
将脚本挂接到对象上。以上类的实现基本上把UI的大部分功能都实现出来了,可以直接拿过来使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Unity3D UI