浅谈使用NGUI的界面架构(二)关于NData

来源:互联网 发布:hadoop 排序算法 编辑:程序博客网 时间:2024/06/03 15:09

浅谈使用NGUI的界面架构(二)关于NData

作者:kUANG tOBY
链接:https://zhuanlan.zhihu.com/p/21306120
来源:知乎

  在刚接触NGUI的时候,我们一般会采用在脚本中获取NGUI 组件的形式给NGUI 组件赋值。有两种选择:一种是在代码中根据路径获取NGUI 组件;另一种是在场景中,直接把组件拖到脚本上。第一种方法的的缺点是需要维护NGUI组件的路径,第二种方法的缺点是替换组件时总是需要重新拖组件。两种方法都比较不方便,这里用第二种来举例。


  打个比方,我们界面右上角要显示玩家拥有的金币总数。于是我们做了个UILabel拖进脚本,在脚本里给它的text赋值显示当前金币数量。



  PagePlayer.cs中:

  1.   public UILabel goldLabel;
  2.     public void SetGold( string gold )
  3.     {
  4.         goldLabel.text = gold;
  5.     }
复制代码

  后来策划需求在左下角和右下角也要显示金币,于是我们又做了两个uilabel放到相应位置,并在脚本里添加变量,把新加的uilabel拖到脚本里。每次金币的值发生变化,就要找到所有的uilabel变量给他们一一赋值。



  PagePlayer.cs中:

  1. public UILabel goldLabel;
  2.     public UILabel goldLabel1;
  3.     public UILabel goldLabel2;
  4.     public void SetGold( string gold )
  5.     {
  6.         goldLabel.text = gold;
  7.         goldLabel1.text = gold;
  8.         goldLabel2.text = gold;
  9.     }

  10. 作者:kUANG tOBY
  11. 链接:https://zhuanlan.zhihu.com/p/21306120
  12. 来源:知乎
  13. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复制代码

  然而可能以后又会增加其它显示金币的界面,每加一个金币的UILabel,就要去脚本里增加一个UILabel 的变量然后在金币变化的时候给它赋值。虽然麻烦,但也能把功能做出来。我们不能就此满足,偷懒是提高生产力的最大动力。

  现在想要简化这个流程,就要实现以下功能。

  1,不需要每次添加金币文字的时候都在脚本中新增一个UILabel变量,并把对应的UILabel组件拖进来。

  2,不需要每次修改金币的时候都要找到所有的金币UILabel变量去修改他们的值。

  初步的解决方案是这样子的:我希望脚本里面有一个值 gold代表的是金币数量。所有的金币UILabel 都跟这个值产生关联。只要修改这个值,所有跟他关联的UILabel 都自动发生变化。另外,在我要添加一个金币UILabel 的时候,我希望它能自动去找页面脚本中的gold变量来发生关联,而不需要我在脚本中改代码。

  具体实现的思路,就是在带有UILabel脚本的物体上加一个脚本,使其与页面脚本种的gold变量发生关联。然后给gold变量加set方法,在这个方法中发一个消息,告知所有和gold有过关联的的UILabel要发生值的改变。这样每次给gold变量赋值的时候,所有与其关联的UILabel就会自动更新显示的内容。

  本着不重复造轮子的原则,在疑似开始造轮子之前一定要Google一下。于是在网上搜出了MVVM模式,NData插件等等。并发现NData不仅可以用于UILabel,还可以用于各种NGUI组件,并有很好的绑定层级管理。

  NData就是基于MVVM模式,其中用户自定义继承EZData.Context的类,就相当于是自定义ViewModel层的内容。

  剩下的问题就是,怎样用这个工具来管理页面。

  根据上文,我把界面分成很多个TweenPage,然后在单例MainPageMgr中统一管理。对于数据,我希望把每个页面的数据也独立出来,即每个页面有一个对应的继承EZData.Context的类,这个页面相关的数据都放在这个类中,然后再由MainPageMgr来统一管理。

  例如有个游戏页面PageInGame,用来显示游戏中获得的金币,钻石和星星。现在新建一个PageInGameContext继承EZData.Context。现在PageInGame页面就有一个model层PageInGame类和一个ViewModel层PageInGameContext类。View层自然就是PageInGame物体下面的NGUI组件了。这样就形成了MVVM模式。

  1. using UnityEngine;
  2. using System.Collections;

  3. public class PageInGameContext : EZData.Context
  4. {
  5.     #region Property Gold

  6.     private readonly EZData.Property<int> _privateGoldProperty = new EZData.Property<int> ();

  7.     public EZData.Property<int> GoldProperty { get { return _privateGoldProperty; } }

  8.     public int Gold {
  9.         get    { return GoldProperty.GetValue (); }
  10.         set    { GoldProperty.SetValue (value); }
  11.     }

  12.     #endregion


  13.     #region Property Diamond

  14.     private readonly EZData.Property<int> _privateDiamondProperty = new EZData.Property<int> ();

  15.     public EZData.Property<int> DiamondProperty { get { return _privateDiamondProperty; } }

  16.     public int Diamond {
  17.         get    { return DiamondProperty.GetValue (); }
  18.         set    { DiamondProperty.SetValue (value); }
  19.     }

  20.     #endregion

  21.     #region Property Star

  22.     private readonly EZData.Property<int> _privateStarProperty = new EZData.Property<int> ();

  23.     public EZData.Property<int> StarProperty { get { return _privateStarProperty; } }

  24.     public int Star {
  25.         get    { return StarProperty.GetValue (); }
  26.         set    { StarProperty.SetValue (value); }
  27.     }

  28.     #endregion

  29. }


  30. public class PageInGame : TweenPage {

  31.     public PageInGameContext Context;

  32.   

  33.     protected override void Awake ()
  34.     {
  35.         base.Awake ();

  36.         MainPageMgr.instance.Context.pageInGame = this;
  37.         Context = MainPageMgr.instance.Context.pageInGameCtx;

  38.     }



  39.     protected override void OnPreBringIn ()
  40.     {
  41.         base.OnPreBringIn ();
  42.        

  43.     }

  44.     protected override void OnPreBringOut ()
  45.     {
  46.         base.OnPreBringOut ();
  47.        
  48.     }
  49. }
复制代码

  在MainPageMgr中有一个MainView Context是用来管理所有页面的Context(下文中继承EZData.Context的类,都统称为Context。):

  1. public class MainPageMgr : PageMgrSingleton<MainPageMgr>
  2. {

  3.     public NguiRootContext View;
  4.     //这个代表页面模型
  5.     public MainView Context;



  6.     void Awake()
  7.     {
  8.       
  9.         Context = new MainView();
  10.         SetContext();


  11.     }

  12.     public void SetContext()
  13.     {
  14.         View.SetContext(Context);
  15.     }
  16. }
复制代码

  MainView.cs

  这样,所有的页面都可以通过MainPageMgr.instance.Context来获取所有页面的Context,如pageXXXContext,也可以获得所有页面的逻辑脚本,如pagXXX。

  在场景里,只需要把页面放在MainPageMgr的下级,然后再通过Master path来绑定到MainPageMgr中的Context就可以了。





  在开发中,可能出现不同的页面共用相同的数据,这种情况就可以直接把两个页面的Master Path绑定到同一个Context上,这样开发起来会方便很多。

  总结:

  引入NData这个插件,主要是为了减少一些对NGUI组件的操作(如获取组件和赋值等),把所有的工作都简化为改变Context中的值,来动态改变NGUI组件的显示。把各个页面的Context都统一管理,是为了更方便地获取数据,但原则上不应该在A页面的model层中去修改B页面Context中的数据,因为这样容易造成混乱。

  使用NData加NGUI,可以很快速地搭建一套页面框架。现在我已经把这两个工具专门打成插件包,开发新项目时直接导进去用,非常方便。


0 0
原创粉丝点击