UMVCSL7——PureMVC框架UI实例
注意!需要先将前面6节课的内容看完再来接着看这里的内容
本章代码关键字
1 2 3 4 5 6 7 8 Notifier.Facade Notifier.SendNotification() Facade.HasMediator() Facade.RegisterMediator() Facade.RetrieveMediator() Facade.HasProxy() Facade.RegisterProxy() Facade.RetrieveProxy()
显示面板
将一个Command
命令与显示面板的通知绑定
在该Command
命令的Execute()
方法内实现显示面板
首先检测是否注册过Mediator
,没有就注册Mediator
,并将该Mediator
关联到View
控件
通过Mediator
来执行显示面板方法
首先我们需要声明一个ShowPanelCommand
的命令,在该命令里实现显示面板的方法
1 2 3 4 5 6 7 8 9 10 11 12 using PureMVC.Interfaces;using PureMVC.Patterns.Command;using UnityEngine;public class ShowPanelCommand : SimpleCommand { public override void Execute (INotification notification ) { base .Execute(notification); } }
然后将该命令在Facade
类里注册,与SHOW_PANEL
这个通知绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 using PureMVC.Patterns.Facade;public class GameFacade : Facade { public static GameFacade Instance => (instance ??= new GameFacade()) as GameFacade; protected override void InitializeController () { base .InitializeController(); RegisterCommand(PureNotification.START_UP, () => { return new StartUpCommand(); }); RegisterCommand(PureNotification.SHOW_PANEL, () => { return new ShowPanelCommand(); }); } public void StartUp () { SendNotification(PureNotification.START_UP); } }
接下来即可在ShowPanelCommand
内实现显示面板的方法
我们可以通过Execute()
传入的notification.body
(通知者传入的对象参数)来判断显示的是哪个面板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 using UnityEngine;public class Main : MonoBehaviour { void Start () { GameFacade.Instance.StartUp(); } void Update () { if (Input.GetKeyDown(KeyCode.M)) { GameFacade.Instance.SendNotification(PureNotification.SHOW_PANEL, "MainPanel" ); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class ShowPanelCommand : SimpleCommand { public override void Execute (INotification notification ) { base .Execute(notification); string panelName = notification.Body.ToString(); switch (panelName) { case "MainPanel" : break ; case "RolePanel" : break ; } } }
继承了Notifier
的类(SimpleCommand
、Mediator
、Proxy
都继承了该类)可以使用Facade
,以直接调用场景上唯一的Facade
因此可以在命令中直接使用Facade
代表的就是唯一的Facade
调用Facade
可以注册Mediator
,以及判断一个Mediator
是否被注册
注意!如果要使用Mediator,一定也要在 Facade
中去注册, command
、 proxy
也一样,如果要通过 Facade
调用就要去注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class ShowPanelCommand : SimpleCommand { public override void Execute (INotification notification ) { base .Execute(notification); string panelName = notification.Body.ToString(); switch (panelName) { case "MainPanel" : if (!Facade.HasMediator(NewMainViewMediator.NAME)) Facade.RegisterMediator(new NewMainViewMediator()); break ; case "RolePanel" : break ; } } }
有mediator
之后,就是可以创建界面,创建预设体,并可以将界面的View
控件,关联到mediator
上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 using PureMVC.Interfaces;using PureMVC.Patterns.Command;using UnityEngine;public class ShowPanelCommand : SimpleCommand { public override void Execute (INotification notification ) { base .Execute(notification); string panelName = notification.Body.ToString(); switch (panelName) { case "MainPanel" : if (!Facade.HasMediator(NewMainViewMediator.NAME)) Facade.RegisterMediator(new NewMainViewMediator()); NewMainViewMediator mainViewMediator = Facade.RetrieveMediator(NewMainViewMediator.NAME) as NewMainViewMediator; if (mainViewMediator.ViewComponent == null ) { GameObject res = Resources.Load<GameObject>("UI/MainPanel" ); GameObject obj = GameObject.Instantiate(res); obj.transform.SetParent(GameObject.Find("Canvas" ).transform, false ); mainViewMediator.ViewComponent = obj.GetComponent<NewMainView>(); } break ; case "RolePanel" : if (!Facade.HasMediator(NewRoleViewMediator.NAME)) Facade.RegisterMediator(new NewRoleViewMediator()); NewRoleViewMediator roleViewMediator = Facade.RetrieveMediator(NewRoleViewMediator.NAME) as NewRoleViewMediator; if (roleViewMediator.ViewComponent == null ) { GameObject res = Resources.Load<GameObject>("UI/RolePanel" ); GameObject obj = GameObject.Instantiate(res); obj.transform.SetParent(GameObject.Find("Canvas" ).transform, false ); roleViewMediator.ViewComponent = obj.GetComponent<NewRoleView>(); } break ; } } }
我们还没有监听View
的用户输入行为,在可以在Mediator
里设置监听(甚至可以不用在Command
内执行关联)
继承了Notifier
的类(SimpleCommand
、Mediator
、Proxy
都继承了该类)可以直接使用SendNotification()
1 2 3 4 5 6 7 8 public void SetView (NewMainView view ){ ViewComponent = view; view.btnRole.onClick.AddListener(() => { SendNotification(PureNotification.SHOW_PANEL, "RolePanel" ); }); }
1 2 3 4 5 6 7 8 9 if (mainViewMediator.ViewComponent == null ){ GameObject res = Resources.Load<GameObject>("UI/MainPanel" ); GameObject obj = GameObject.Instantiate(res); obj.transform.SetParent(GameObject.Find("Canvas" ).transform, false ); mainViewMediator.SetView(obj.GetComponent<NewMainView>()); }
隐藏面板
将一个Command
命令与隐藏面板的通知绑定
在该Command
命令的Execute()
方法内实现隐藏面板
得到Mediator
再得到Mediator
中的View
通过View
来删除或隐藏UI对象
隐藏的目的,得到Mediator
再得到Mediator
中的View
,通过View
来删除或隐藏UI对象
这里通过外部通知者传入要隐藏面板的Mediator
注:这里notification.Body is Mediator mediator
使用了模式匹配的类型模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 using PureMVC.Interfaces;using PureMVC.Patterns.Command;using PureMVC.Patterns.Mediator;using UnityEngine;public class HidePanelCommand : SimpleCommand { public override void Execute (INotification notification ) { base .Execute(notification); if (notification.Body is Mediator mediator && mediator.ViewComponent != null ) { GameObject.Destroy((mediator.ViewComponent as MonoBehaviour).gameObject); mediator.ViewComponent = null ; } } }
之后再在外部使用通知隐藏面板即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 using UnityEngine;public class Main : MonoBehaviour { void Start () { GameFacade.Instance.StartUp(); } void Update () { if (Input.GetKeyDown(KeyCode.M)) { GameFacade.Instance.SendNotification(PureNotification.SHOW_PANEL, "MainPanel" ); } else if (Input.GetKeyDown(KeyCode.N)) { GameFacade.Instance.SendNotification(PureNotification.HIDE_PANEL, GameFacade.Instance.RetrieveMediator(NewMainViewMediator.NAME)); } } }
我们还没有监听View
的用户输入行为,在可以在Mediator
里设置监听(甚至可以不用在Command
内执行关联)
继承了Notifier
的类(SimpleCommand
、Mediator
、Proxy
都继承了该类)可以直接使用SendNotification()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 using PureMVC.Interfaces;using PureMVC.Patterns.Mediator;public class NewRoleViewMediator : Mediator { public void SetView (NewRoleView view ) { ViewComponent = view; view.btnClose.onClick.AddListener(() => { SendNotification(PureNotification.HIDE_PANEL, this ); }); view.btnLevUp.onClick.AddListener(() => { }); } }
更新通知
往往显示了面板后,需要在这里进行第一次UI控件更新,就需要把数据作为参数一起传出去
但是目前的Facade
是没有Proxy
的数据的,因此我们需要为Proxy
注册,我们一般在启动函数里注册Proxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 using PureMVC.Patterns.Facade;public class GameFacade : Facade { public void StartUp () { SendNotification(PureNotification.START_UP); if (!HasProxy(PlayerProxy.NAME)) RegisterProxy(new PlayerProxy()); } }
之后就可以通过Facade
调用RetrieveProxy()
方法传入PlayerProxy.NAME
来获取Proxy
,进而通过Proxy.data
来获取数据
同时要注意,通知是不一定需要和command
命令绑定在一起的,在Mediator
内也可以设置监听哪些通知,执行对应的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class NewMainViewMediator : Mediator { public override string [] ListNotificationInterests () { return new string [] { PureNotification.UPDATE_PLAYER_INFO }; } public override void HandleNotification (INotification notification ) { switch (notification.Name) { case PureNotification.UPDATE_PLAYER_INFO: (ViewComponent as NewMainView).UpdateInfo(notification.Body as PlayerDataObject); break ; } } } public class NewRoleViewMediator : Mediator { public override string [] ListNotificationInterests () { return new string [] { PureNotification.UPDATE_PLAYER_INFO }; } public override void HandleNotification (INotification notification ) { switch (notification.Name) { case PureNotification.UPDATE_PLAYER_INFO: (ViewComponent as NewRoleView).UpdateInfo( notification.Body as PlayerDataObject ); break ; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public override void Execute (INotification notification ){ base .Execute(notification); string panelName = notification.Body.ToString(); switch (panelName) { case "MainPanel" : SendNotification(PureNotification.UPDATE_PLAYER_INFO, Facade.RetrieveProxy(PlayerProxy.NAME).Data); break ; case "RolePanel" : SendNotification(PureNotification.UPDATE_PLAYER_INFO, Facade.RetrieveProxy(PlayerProxy.NAME).Data); break ; } }
接下来监听升级按钮的输入,实现升级的方法
这里我们再声明一个用于升级的LevUpCommand
命令,以及对应的通知,并在Facade
内注册它
1 2 3 4 public class PureNotification { public const string LEVEL_UP = "levelUp" ; }
注:这里Facade.RetrieveProxy(PlayerProxy.NAME) is PlayerProxy playerProxy
使用了模式匹配的类型模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 using PureMVC.Interfaces;using PureMVC.Patterns.Command;public class LevUpCommand : SimpleCommand { public override void Execute (INotification notification ) { base .Execute(notification); if (Facade.RetrieveProxy(PlayerProxy.NAME) is PlayerProxy playerProxy) { playerProxy.LevelUp(); SendNotification(PureNotification.UPDATE_PLAYER_INFO, playerProxy.Data); } } }
1 2 3 4 5 6 7 8 9 10 protected override void InitializeController (){ base .InitializeController(); RegisterCommand(PureNotification.START_UP, () => { return new StartUpCommand(); }); RegisterCommand(PureNotification.SHOW_PANEL, () => { return new ShowPanelCommand(); }); RegisterCommand(PureNotification.HIDE_PANEL, () => { return new HidePanelCommand(); }); RegisterCommand(PureNotification.LEVEL_UP, () => { return new LevUpCommand(); }); }
之后在Mediator
内监听升级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public void SetView (NewRoleView view ){ ViewComponent = view; view.btnClose.onClick.AddListener(() => { SendNotification(PureNotification.HIDE_PANEL, this ); }); view.btnLevUp.onClick.AddListener(() => { SendNotification(PureNotification.LEVEL_UP); }); }
值得一提的是,Mediator
内每次对其关联的ViewComponent
进行操作时,都应当判空,避免出现问题
1 2 3 4 5 6 7 8 9 10 11 public override void HandleNotification (INotification notification ){ switch (notification.Name) { case PureNotification.UPDATE_PLAYER_INFO: if (ViewComponent != null ) (ViewComponent as NewRoleView).UpdateInfo( notification.Body as PlayerDataObject ); break ; } }