PureMVC和Unity3D的UGUI制作一個簡單的員工管理系統實例

運行實例演示.png

前言:

1.關于PureMVC:

MVC框架在很多項目當中擁有廣泛的應用,很多時候做項目前人開坑開了一半就消失了,后人為了填補各種的坑就遭殃的不得了。嘛,程序猿大家都不喜歡像文案策劃一樣組織文字寫東西,也不喜歡看別人留下不清不楚的文檔,還不如看代碼來得實在。剛開始新人看代碼是看得頭暈,因為這樣那樣的東西不一定能完全猜得透。而老人家就算有經驗和閱歷,也沒有這么多的體力去看一個龐大而又復雜的糟糕項目。因為這種需求,Unity3D的程序猿就統一組織起來,想做一個完整規范的程序框架,而這時,PureMVC就誕生了。我個人喜歡PureMVC的原因也很簡單,因為它簡單粗暴,和Unity3D之間沒有依賴性,加上又開源,真的遇到Bug能拿到源代碼來調試也是很容易執行的。Unity3D應用商店還有一個同類產品叫uFrame Game Framework,它對Unity版本有著依賴,拖視圖雖然方便,但是一旦出bug真的改得夠嗆的,所以不推薦使用它。下文便是使用PureMVC和Unity3D的UGUI制作一個簡單的員工管理系統實例。

2.通過MVC模式在Unity項目當中應用的特別提醒:

(1)Unity3D是基于組件設計的,如果沒有好的規劃,組件之間會產生復雜的調用關系,導致組件之間復雜的依賴,從而破壞了整個系統結構,因此需要設計時確定組件的層次關系,確保依賴關系只存在于下層對上層。而這個是業務邏輯設計問題,PureMVC幫不了你。
(2)僅僅用上MVC,解決不了什么問題,或許解決了1%,剩下的99%就被挪到了MVC的C里,當你慶祝MVC竣工時,99%的問題在那里默默的微笑的看著你。(話說以前寫PHP的CI框架時候,一堆東西扔到XxxAction.Class.php里面,發現和擺的亂七八糟的架構沒區別,只是大家都習慣了這套框架的規矩,看代碼找某個東西稍微好找而已,本質上還是考驗基本功和對項目的熟悉程度的,23333)

3.PureMVC通過4種pattern實現隔離變化:

(1)facade非常適合將UI界面對游戲數據的依賴解耦,將UI操作數據的請求封裝在facade 接口里面,同時數據變化對UI的影響可以通過notification事件通知來實現,該模式應用得非常常見。
(2)command模式統一對對象的操作,將鍵盤輸入,網絡輸入輸出統一成command來操控游戲對象。
(3)proxy維護數據,提供某塊數據統一的初始化,訪問和修改接口。
(4)mediator沒怎么用過,我們的游戲中的UI界面每次變化一般都是整體更新的,不常用局部更新。
以上4中pattern請務必牢牢記住,請務必牢牢記住,請務必牢牢記住。重要的事情要說3便。

4.PureMVC的流程示意圖

(1)在puremvc中,model/view/controller統一是由Facade類的單件實例來統籌管理的。
(2)PureMVC的基本流程:啟動PureMVC—>建立Mediator來操作視覺元素(按鈕與文本框)—>點擊按鈕發送Notification->文本框接收Notification改變內容。
(3)大致流程可理解為:通過Facade類的單件實例(即:統一的門面) 啟動 puremvc環境,啟動同時注冊Command對象(相當于asp.net mvc中的controller),然后Command通過與之關聯的facade(即前面的單件實例)來注冊Mediator(中介者:用于把View與Command聯系起來)。
(4)當UI界面(即View)上有動靜時(比如按鈕點擊了之類),與之關聯的Mediator(中介者)會發送通知給facade,然后facade會調用command對象執行相關的處理。(即:消息響應)


PureMVC示意圖.png

一.引入PureMVC的插件

1.下載PureMVC

請訪問地址
https://github.com/PureMVC/puremvc-csharp-standard-framework/wiki

安裝

2.把PureMVC.DotNET.35.dll放到Plugins里面就好了。

QA

3.這里有一個很簡單的基本案例可以參考一下
http://www.open-open.com/lib/view/open1452657515480.html

二.動手配置文件

1.需要完成的實例如下:

實現的界面效果.png

2.具體實現的目標:

(1)在Scripts文件夾下,分別設置模型、視圖、控制器對應的文件夾Model、View、Controller,分別放置處理數據模型的腳本、處理顯示視圖的腳本、處理邏輯控制的腳本。
(2)如界面,一個Unity3D和UGUI制作的簡單員工管理系統,Employee Admin,其中員工界面Users顯示有哪些員工在登記范圍內,而New和Delete分別是添加和刪除某個員工的信息。然后下面的員工信息界面User Profile則是對員工信息的一個具體編輯和修正。

三.主要實現步驟

1.啟動文件AppFacade.cs 作為PureMVC框架的入口文件。

using UnityEngine;
using System.Collections;
using PureMVC.Patterns;
using PureMVC.Interfaces;

//Facade模式的單例
public class ApplicationFacade : Facade
{
    //實例化函數,保證單例模式(Singleton)運行該函數
    public new static IFacade Instance
    {
        get
        {
            if(m_instance == null)
            {
                lock(m_staticSyncRoot)
                {
                    if (m_instance == null)
                    {
                        Debug.Log("ApplicationFacade");
                        m_instance = new ApplicationFacade();
                    }
                }
            }
            return m_instance;
        }
    }
    //啟動PureMVC的入口函數
    public void Startup(MainUI mainUI)
    {
        Debug.Log("Startup() to SendNotification.");
        SendNotification(EventsEnum.STARTUP, mainUI);
    }
    //該類的構造器
    protected ApplicationFacade()
    {

    }
    //設置靜態
    static ApplicationFacade()
    {

    }
    //初始化控制器函數
    protected override void InitializeController()
    {
        Debug.Log("InitializeController()");
        base.InitializeController();
        RegisterCommand(EventsEnum.STARTUP, typeof(StartupCommand));
        RegisterCommand(EventsEnum.DELETE_USER, typeof(DeleteUserCommand));
    }
}

2.對PureMVC需要處理的事件用EventsEnum.cs存放

using UnityEngine;
using System.Collections;

//處理事件的枚舉
public class EventsEnum
{
    public const string STARTUP = "startup";//啟動事件

    public const string NEW_USER = "newUser";//新建用戶
    public const string DELETE_USER = "deleteUser";//刪除用戶
    public const string CANCEL_SELECTED = "cancelSelected";//取消選擇

    public const string USER_SELECTED = "userSelected";//選擇用戶
    public const string USER_ADDED = "userAdded";//添加用戶
    public const string USER_UPDATED = "userUpdated";//更新用戶
    public const string USER_DELETED = "userDeleted";//刪除用戶

    public const string ADD_ROLE = "addRole";//添加角色
    public const string ADD_ROLE_RESULT = "addRoleResult";//查詢添加角色的結果
}

3.然后在Unity的場景中創建一個MainUI.cs文件,掛在需要啟動PureMVC的組件上。就可以啟動了。

using UnityEngine;
using System.Collections;

//處理該UI場景的入口
public class MainUI : MonoBehaviour
{
    public UserList userList;
    public UserForm userForm;
    //啟動函數
    void Awake()
    {
        //啟動PureMVC程序,執行StartUP()方法
        ApplicationFacade facade = ApplicationFacade.Instance as ApplicationFacade;
        facade.Startup(this);
    }
}

4.對Controller部分進行處理

然后我們對執行邏輯的處理事件進行補充。新建一個文件夾Controller,暫時先放置StartupCommand.cs和DeleteUserCommand.cs。處理上述所說的邏輯事件
首先,處理啟動事件

using UnityEngine;
using System.Collections;
using PureMVC.Patterns;
using PureMVC.Interfaces;

//啟動事件
public class StartupCommand : SimpleCommand, ICommand
{
    //復寫原有的Execute執行函數
    public override void Execute(INotification notification)
    {
        //注冊統一的數據接口UserProxy,給其他事件處理
        Debug.Log("StartupCommand.Execute()");
        Facade.RegisterProxy(new UserProxy());

        //注冊局部界面Mediator,給其他事件處理
        MainUI mainUI = notification.Body as MainUI;
        Facade.RegisterMediator(new UserListMediator(mainUI.userList));
        Facade.RegisterMediator(new UserFormMediator(mainUI.userForm));
    }
}

其次,處理刪除用戶事件

using PureMVC.Patterns;
using PureMVC.Interfaces;

//刪除用戶事件
public class DeleteUserCommand : SimpleCommand, ICommand
{
   //復寫原有的Execute執行函數
    public override void Execute(INotification notification)
    {
        //獲取要刪除的對象user
        UserVO user = (UserVO)notification.Body;
        //獲取處理數據操作的userProxy
        UserProxy userProxy = (UserProxy)Facade.RetrieveProxy(UserProxy.NAME);

        //操作數據,刪除user
        userProxy.DeleteItem(user);
        //刪除完畢,廣播USER_DELETED進行通知
        SendNotification(EventsEnum.USER_DELETED);
    }
}

5.對Model部分進行處理

然后是對Model模型數據的定義哈,首先要記錄的信息用UserVO來表示

using UnityEngine;
using System.Collections;
//顯示用的數據信息UserViewObject
public class UserVO
{
    //用戶名
    public string UserName
    {
        get { return m_userName; }
    }
    private string m_userName = "";
    //名字
    public string FirstName
    {
        get { return m_firstName; }
    }
    private string m_firstName = "";
    //姓氏
    public string LastName
    {
        get { return m_lastName; }
    }
    private string m_lastName = "";
    //郵箱
    public string Email
    {
        get { return m_email; }
    }
    private string m_email = "";
    //密碼
    public string Password
    {
        get { return m_password; }
    }
    private string m_password = "";
    //部門
    public string Department
    {
        get { return m_department; }
    }
    private string m_department = "";
    //是否合法
    public bool IsValid
    {
        get
        {
            return !string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password);
        }
    }
    //合并名字
    public string GivenName
    {
        get { return LastName + ", " + FirstName; }
    }
    //構造器
    public UserVO()
    {
    }
    //構造函數
    public UserVO(string uname, string fname, string lname, string email, string password, string department)
    {
        if (uname != null) m_userName = uname;
        if (fname != null) m_firstName = fname;
        if (lname != null) m_lastName = lname;
        if (email != null) m_email = email;
        if (password != null) m_password = password;
        if (department != null) m_department = department;
    }
}

接著對操作數據的UserProxy進行補充

using UnityEngine;
using System.Collections.Generic;
using PureMVC.Patterns;
using PureMVC.Interfaces;

//數據操作
public class UserProxy : Proxy, IProxy
{
    public new const string NAME = "UserProxy";

    //返回數據操作類
    public IList<UserVO> Users
    {
        get { return (IList<UserVO>) base.Data; }
    }

    //構造函數,添加幾條數據進去先
    public UserProxy():base(NAME, new List<UserVO>())
    {
        Debug.Log("UserProxy()");
        //添加幾條測試用的數據        
        AddItem(new UserVO("lstooge", "Larry", "Stooge", "larry@stooges.com", "ijk456", "ACCT"));
        AddItem(new UserVO("cstooge", "Curly", "Stooge", "curly@stooges.com", "xyz987", "SALES"));
        AddItem(new UserVO("mstooge", "Moe", "Stooge", "moe@stooges.com", "abc123", "PLANT"));
        AddItem(new UserVO("lzh", "abc", "def", "lzh@stooges.com", "abc123", "IT"));
    }

    //添加數據的方法
    public void AddItem(UserVO user)
    {
        Users.Add(user);
    }

    //更新數據的方法
    public void UpdateItem(UserVO user)
    {
        for (int i = 0; i < Users.Count; i++)
        {
            if (Users[i].UserName.Equals(user.UserName))
            {
                Users[i] = user;
                break;
            }
        }
    }

    //刪除數據的方法
    public void DeleteItem(UserVO user)
    {
        for (int i = 0; i < Users.Count; i++)
        {
            if (Users[i].UserName.Equals(user.UserName))
            {
                Users.RemoveAt(i);
                break;
            }
        }
    }
}

6.接下來對VIew部分進行實現

顯示用戶界面列表的UserList和填寫用戶具體信息的UserForm
列表單條數據部分

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

//UserList列表當中單條數據信息
public class UserList_Item : MonoBehaviour
{
    //定義UI組件
    public Text txt_userName;//用戶名文本框
    public Text txt_firstName;//名字文本框
    public Text txt_lastName;//姓氏文本框
    public Text txt_email;//郵件文本框
    public Text txt_department;//部門文本框

    //定義User信息類
    public UserVO userData;

    //更新User類
    public void UpdateData(UserVO data)
    {
        //獲取需要更改的User信息
        this.userData = data;

        //更改UI的文字信息
        txt_userName.text = data.UserName;
        txt_firstName.text = data.FirstName;
        txt_lastName.text = data.LastName;
        txt_email.text = data.Email;
        txt_department.text = data.Department;
    }
}

用戶列表部分

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;

//UserList用戶界面列表部分
public class UserList : MonoBehaviour
{
    //定義UI組件
    public Text txt_userCount;//用戶列表文本框
    public UGUI_MyToggleGroup myToggleGroup;//用戶列表滑動條
    public Button btn_New;//新建按鈕
    public Button btn_Delete;//刪除按鈕
    public UserList_Item itemPrefab;//單個列表文件的預置體
    List<UserList_Item> itemList = new List<UserList_Item>();//臨時存列表

    //定義事件操作
    public System.Action NewUser;//添加用戶事件
    public System.Action DeleteUser;//刪除用戶事件
    public System.Action SelectUser;//選擇用戶事件

    //定義數據
    public UserVO SelectedUserData;//列表中選擇好的用戶
    private IList<UserVO> m_currentUsers;//當前選擇的用戶

    //開始函數
    void Start ()
    {
        itemPrefab.gameObject.SetActive(false);

        myToggleGroup.onToggleChange.AddListener(onSelectUserItem);
        btn_New.onClick.AddListener(onClick_btn_New);
        btn_Delete.onClick.AddListener(onClick_btn_Delete);

        UpdateButtons();
    }
    //加載用戶
    public void LoadUsers(IList<UserVO> list)
    {
        m_currentUsers = list;
        RefreshUI(list);
    }
    //點擊新建
    void onClick_btn_New()
    {
        if (NewUser != null) NewUser();
    }
    //點擊刪除
    void onClick_btn_Delete()
    {
        if (DeleteUser != null) DeleteUser();
    }
    //選擇物體
    void onSelectUserItem(Toggle itemToggle)
    {
        if (itemToggle == null)
        {
            return;
        }

        UserList_Item item = itemToggle.GetComponent<UserList_Item>();
        this.SelectedUserData = item.userData;
        UpdateButtons();
        if (SelectUser != null) SelectUser();

    }
    //取消選擇
    public void Deselect()
    {
        myToggleGroup.toggleGroup.SetAllTogglesOff();
        this.SelectedUserData = null;
        UpdateButtons();
    }
    //刷新UI
    void RefreshUI(IList<UserVO> datas)
    {
        ClearItems();
        foreach (var data in datas)
        {
            UserList_Item item = CreateItem();
            item.UpdateData(data);
            itemList.Add(item);
        }
        txt_userCount.text = datas.Count.ToString();
    }
    //新建列表項目
    UserList_Item CreateItem()
    {
        UserList_Item item = GameObject.Instantiate<UserList_Item>(itemPrefab);
        item.transform.SetParent(itemPrefab.transform.parent);
        item.gameObject.SetActive(true);
        item.transform.localScale = Vector3.one;
        item.transform.localPosition = Vector3.zero;

        return item;
    }
    //清空列表
    void ClearItems()
    {
        foreach(var item in itemList)
        {
            Destroy(item.gameObject);
        }
        itemList.Clear();
    }
    //更新按鈕
    private void UpdateButtons()
    {
        btn_Delete.interactable = (SelectedUserData != null);
    }
}

用戶個人信息部分

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.EventSystems;

//用戶個人信息表單模式?編輯:新增
public enum UserFormMode
{
    ADD,
    EDIT,
}
//用戶個人信息表單
public class UserForm : MonoBehaviour
{
    //UI項的定義
    public InputField txt_firstName;
    public InputField txt_lastName;
    public InputField txt_email;
    public InputField txt_userName;
    public InputField txt_password;
    public InputField txt_confirmPassword;
    public InputField txt_department;
    public Button btn_updateUser;
    public Button btn_cancel;

    //其他
    public System.Action AddUser;
    public System.Action UpdateUser;
    public System.Action CancelUser;

    //用戶信息獲取
    public UserVO User
    {
        get { return m_user; }
    }
    private UserVO m_user;

    //用戶信息表單
    public UserFormMode Mode
    {
        get { return m_mode; }
    }
    private UserFormMode m_mode = UserFormMode.ADD;

    //開始
    void Start ()
    {
        //設置UI
        btn_updateUser.onClick.AddListener(btn_updateUser_Click);
        btn_cancel.onClick.AddListener(btn_cancel_Click);

        txt_userName.onValueChange.AddListener(InputField_onValueChange);
        txt_password.onValueChange.AddListener(InputField_onValueChange);
        txt_confirmPassword.onValueChange.AddListener(InputField_onValueChange);

        UpdateButtons();
    }

    //顯示當前用戶信息
    public void ShowUser(UserVO user, UserFormMode mode)
    {
        m_mode = mode;
        if (user == null)
        {
            ClearForm();
        }
        else
        {
            m_user = user;
            txt_firstName.text = user.FirstName;
            txt_lastName.text = user.LastName;
            txt_email.text = user.Email;
            txt_userName.text = user.UserName;
            txt_password.text = txt_confirmPassword.text = user != null ? user.Password : "";
            txt_department.text = user.Department;
            //txt_firstName.ActivateInputField();
            EventSystem.current.SetSelectedGameObject(txt_firstName.gameObject);
            //txt_firstName.MoveTextEnd(false);
            txt_firstName.caretPosition = txt_firstName.text.Length - 1;
            UpdateButtons();
        }
    }

    //更新按鈕
    private void UpdateButtons()
    {
        if (btn_updateUser != null)
        {
            btn_updateUser.interactable = (txt_firstName.text.Length > 0 && txt_password.text.Length > 0 && txt_password.text.Equals(txt_confirmPassword.text));
        }
    }

    //清空表單
    public void ClearForm()
    {
        m_user = null;
        txt_firstName.text = txt_lastName.text = txt_email.text = txt_userName.text = "";
        txt_password.text = txt_confirmPassword.text = "";
        txt_department.text = "";
        UpdateButtons();
    }

    //更新用戶信息
    void btn_updateUser_Click()
    {
        m_user = new UserVO(
            txt_userName.text, txt_firstName.text, 
            txt_lastName.text, txt_email.text, 
            txt_password.text, txt_department.text);

        if (m_user.IsValid)
        {
            if (m_mode == UserFormMode.ADD)
            {
                if (AddUser != null) AddUser();
            }
            else
            {
                if (UpdateUser != null) UpdateUser();
            }
        }
    }

    //取消信息
    void btn_cancel_Click()
    {
        if (CancelUser != null) CancelUser();
    }

    //輸入
    void InputField_onValueChange(string value)
    {
        UpdateButtons();
    }
}

最后,對局部更新UI的行為進行完善Mediator

using UnityEngine;
using System.Collections;
using PureMVC.Patterns;
using PureMVC.Interfaces;
using System.Collections.Generic;
//更新UserList部分
public class UserListMediator : Mediator, IMediator
{
    private UserProxy userProxy;

    public new const string NAME = "UserListMediator";

    private UserList View
    {
        get { return (UserList)ViewComponent; }
    }

    public UserListMediator(UserList userList)
            : base(NAME, userList)
    {
        Debug.Log("UserListMediator()");
        userList.NewUser += userList_NewUser;
        userList.DeleteUser += userList_DeleteUser;
        userList.SelectUser += userList_SelectUser;
    }

    public override void OnRegister()
    {
        Debug.Log("UserListMediator.OnRegister()");
        base.OnRegister();
        userProxy = Facade.RetrieveProxy(UserProxy.NAME) as UserProxy;
        View.LoadUsers(userProxy.Users);
    }

    void userList_NewUser()
    {
        UserVO user = new UserVO();
        SendNotification(EventsEnum.NEW_USER, user);
    }

    void userList_DeleteUser()
    {
        SendNotification(EventsEnum.DELETE_USER, View.SelectedUserData);
    }

    void userList_SelectUser()
    {
        SendNotification(EventsEnum.USER_SELECTED, View.SelectedUserData);
    }

    public override IList<string> ListNotificationInterests()
    {
        IList<string> list = new List<string>();
        list.Add(EventsEnum.USER_DELETED);
        list.Add(EventsEnum.CANCEL_SELECTED);
        list.Add(EventsEnum.USER_ADDED);
        list.Add(EventsEnum.USER_UPDATED);
        return list;
    }

    public override void HandleNotification(INotification notification)
    {
        switch(notification.Name)
        {
            case EventsEnum.USER_DELETED:
                View.Deselect();
                View.LoadUsers(userProxy.Users);
                break;
            case EventsEnum.CANCEL_SELECTED:
                View.Deselect();
                break;
            case EventsEnum.USER_ADDED:
                View.Deselect();
                View.LoadUsers(userProxy.Users);
                break;
            case EventsEnum.USER_UPDATED:
                View.Deselect();
                View.LoadUsers(userProxy.Users);
                break;
        }
    }
}

using UnityEngine;
using System.Collections;
using PureMVC.Patterns;
using PureMVC.Interfaces;
using System.Collections.Generic;
//更新UserForm部分
public class UserFormMediator : Mediator, IMediator
{
    private UserProxy userProxy;

    public new const string NAME = "UserFormMediator";

    private UserForm View
    {
        get { return (UserForm)ViewComponent; }
    }

    public UserFormMediator(UserForm viewComponent)
        : base(NAME, viewComponent)
    {
        Debug.Log("UserFormMediator()");

        View.AddUser += UserForm_AddUser;
        View.UpdateUser += UserForm_UpdateUser;
        View.CancelUser += UserForm_CancelUser;
    }

    public override void OnRegister()
    {
        base.OnRegister();
        userProxy = Facade.RetrieveProxy(UserProxy.NAME) as UserProxy;
    }

    void UserForm_AddUser()
    {
        UserVO user = View.User;
        userProxy.AddItem(user);
        SendNotification(EventsEnum.USER_ADDED, user);
        View.ClearForm();
    }

    void UserForm_UpdateUser()
    {
        UserVO user = View.User;
        userProxy.UpdateItem(user);
        SendNotification(EventsEnum.USER_UPDATED, user);
        View.ClearForm();
    }

    void UserForm_CancelUser()
    {
        SendNotification(EventsEnum.CANCEL_SELECTED);
        View.ClearForm();
    }

    public override IList<string> ListNotificationInterests()
    {
        IList<string> list = new List<string>();
        list.Add(EventsEnum.NEW_USER);
        list.Add(EventsEnum.USER_DELETED);
        list.Add(EventsEnum.USER_SELECTED);
        return list;
    }

    public override void HandleNotification(INotification note)
    {
        UserVO user;
        switch (note.Name)
        {
            case EventsEnum.NEW_USER:
                user = (UserVO)note.Body;
                View.ShowUser(user, UserFormMode.ADD);
                break;

            case EventsEnum.USER_DELETED:
                View.ClearForm();
                break;

            case EventsEnum.USER_SELECTED:
                user = (UserVO)note.Body;
                View.ShowUser(user, UserFormMode.EDIT);
                break;

        }
    }
}

補充,UI的選擇部分

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

[RequireComponent(typeof(Toggle))]
public class UGUI_MyToggle : MonoBehaviour
{    
    [SerializeField]Toggle toggle;
    [SerializeField]UGUI_MyToggleGroup myToggleGroup;

    void Start()
    {
        if (toggle == null) toggle = this.GetComponent<Toggle>();
        if (myToggleGroup == null) myToggleGroup = toggle.group.GetComponent<UGUI_MyToggleGroup>();

        toggle.onValueChanged.AddListener(onToggle);
    }

    void onToggle(bool value)
    {
        if(value)
        {
            myToggleGroup.ChangeToggle(toggle);
        }
    }
}

//[lzh]
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using System.Collections;

public class ToggleEvent : UnityEvent<Toggle> { }

[RequireComponent(typeof(ToggleGroup))]
public class UGUI_MyToggleGroup : MonoBehaviour
{
public ToggleGroup toggleGroup;
public ToggleEvent onToggleChange = new ToggleEvent();

void Start()
{
    if (toggleGroup == null) toggleGroup = this.GetComponent<ToggleGroup>();
}

public void ChangeToggle(Toggle toggle)
{
    onToggleChange.Invoke(toggle);
}

}


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容