Unity 3D Framework Designing(3)——构建View和ViewModel的生命周期
> 对于一个View而言,本质上是一个MonoBehaviour。它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等。这些是非常好的方法,可以让开发者在各个阶段去执行自定义的代码。但唯一遗憾的事,这些方法是有引擎调用,并且颗粒度不够细。本文将谈谈怎样构建View和ViewModel的生命周期。
### View的生命周期 ###
**举个栗子,一个View的显示会有如下过程:**
- 初始化操作
- 激活当前对象,SetActive(true)
- 显示当前对象,包括localScale=Vector3.one,并且alpha从0->1
- 当View显示之后,执行某些callBack方法,OnCompleted或者OnSuccess
**再举个栗子,一个View隐藏会有如下过程:**
- 隐藏当前对象,包括localScale=Vector3.zero,并且alpha从1->0
- 当View隐藏之后,执行某些callBack方法,OnCompleted或者OnSuccess
- 不激活当前对象,SetActive(false)
- Destory 当前对象时的处理方法
### ViewModel的生命周期 ###
对于View而言,它并不处理复杂的业务逻辑,View只负责显示。比如在哪个阶段去数据库或者其他地方去拿数据,这不归View来处理。这理所应当交给ViewModel去处理,ViewModel只要知道View什么阶段让我去拿数据即可。
所以对应的ViewModel也有生命周期,它对应了View的生命周期,ViewModel的生命周期包括:
- 初始化操作
- View在**显示前**处理的逻辑
- View在**显示后**时处理的逻辑
- View在**隐藏前**处理的逻辑
- View在**隐藏后**处理的逻辑
- View被**销毁时**应该处理的逻辑
### 构建生命周期 ###
有了上述的分析之后,就需要落实,如何去构建View和ViewModel的生命周期了。
Overview图如下所示:

- OnInitialize:用来初始化View。结合前几篇文章,OnInitialize 用来注册 **OnBindingContextChanged** 事件以及属性绑定(Binder.Add)
- OnAppear:用来激活View
- OnReveal:用来显示View,比如以动画形式(Fade)显示呢还是直接显示
- OnRevealed:当View显示完毕时,执行的额外操作,是一个委托(**Action**)
- OnHide:开始隐藏View
- OnHidden:同OnReveal一样,可以以动画形式慢慢隐藏或者直接隐藏
- OnDisappear:隐藏完毕后SetActive(false)不激活当前对象
- OnDestory:当View被Detory时自动调用OnDestory方法
将这些方法放入UnityGuiView基类中:
[RequireComponent(typeof(CanvasGroup))]
public abstract class UnityGuiView:MonoBehaviour,IView where T:ViewModelBase
{
private bool _isInitialized;
public bool destroyOnHide;
protected readonly PropertyBinder Binder=new PropertyBinder();
public readonly BindableProperty ViewModelProperty = new BindableProperty();
///
///
public Action RevealedAction { get; set; }
///
///
public Action HiddenAction { get; set; }
public T BindingContext
{
get { return ViewModelProperty.Value; }
set
{
if (!_isInitialized)
{
OnInitialize();
_isInitialized = true;
}
//触发OnValueChanged事件
ViewModelProperty.Value = value;
}
}
public void Reveal(bool immediate = false, Action action = null)
{
if (action!=null)
{
RevealedAction += action;
}
OnAppear();
OnReveal(immediate);
OnRevealed();
}
public void Hide(bool immediate = false, Action action = null)
{
if (action!=null)
{
HiddenAction += action;
}
OnHide(immediate);
OnHidden();
OnDisappear();
}
///
///
protected virtual void OnInitialize()
{
//无所ViewModel的Value怎样变化,只对OnValueChanged事件监听(绑定)一次
ViewModelProperty.OnValueChanged += OnBindingContextChanged;
}
///
///
public virtual void OnAppear()
{
gameObject.SetActive(true);
BindingContext.OnStartReveal();
}
///
///
///
private void OnReveal(bool immediate)
{
if (immediate)
{
//立即显示
transform.localScale = Vector3.one;
GetComponent().alpha = 1;
}
else
{
StartAnimatedReveal();
}
}
///
///
public virtual void OnRevealed()
{
BindingContext.OnFinishReveal();
//回掉函数
if (RevealedAction!=null)
{
RevealedAction();
}
}
private void OnHide(bool immediate)
{
BindingContext.OnStartHide();
if (immediate)
{
//立即隐藏
transform.localScale = Vector3.zero;
GetComponent().alpha = 0;
}
else
{
StartAnimatedHide();
}
}
///
///
public virtual void OnHidden()
{
//回掉函数
if (HiddenAction!=null)
{
HiddenAction();
}
}
///
///
public virtual void OnDisappear()
{
gameObject.SetActive(false);
BindingContext.OnFinishHide();
if (destroyOnHide)
{
//销毁
Destroy(this.gameObject);
}
}
///
///
public virtual void OnDestroy()
{
if (BindingContext.IsRevealed)
{
Hide(true);
}
BindingContext.OnDestory();
BindingContext = null;
ViewModelProperty.OnValueChanged = null;
}
///
///
protected virtual void StartAnimatedReveal()
{
var canvasGroup = GetComponent();
canvasGroup.interactable = false;
transform.localScale = Vector3.one;
canvasGroup.DOFade(1, 0.2f).SetDelay(0.2f).OnComplete(() =>
{
canvasGroup.interactable = true;
});
}
///
///
protected virtual void StartAnimatedHide()
{
var canvasGroup = GetComponent();
canvasGroup.interactable = false;
canvasGroup.DOFade(0, 0.2f).SetDelay(0.2f).OnComplete(() =>
{
transform.localScale = Vector3.zero;
canvasGroup.interactable = true;
});
}
///
/// 利用反射+=/-=OnValuePropertyChanged
///
private void OnBindingContextChanged(T oldValue, T newValue)
{
Binder.Unbind(oldValue);
Binder.Bind(newValue);
}
}
而ViewMode中就现对而言比较简单了,处理View处理不了的逻辑:
public virtual void OnStartReveal()
{
IsRevealInProgress = true;
//在开始显示的时候进行初始化操作
if (!_isInitialized)
{
OnInitialize();
_isInitialized = true;
}
}
public virtual void OnFinishReveal()
{
IsRevealInProgress = false;
IsRevealed = true;
}
public virtual void OnStartHide()
{
IsHideInProgress = true;
}
public virtual void OnFinishHide()
{
IsHideInProgress = false;
IsRevealed = false;
}
public virtual void OnDestory()
{
}
> 值得注意的事,以上不管是View还是ViewModel与生命周期相关的方法,都是虚方法(**virtual**),这就意味这子类可以Override掉。比如某些场景下需要将View从左边或者右边移入,可以在初始化时指定偏移距离。又或者不想用默认的DoTween特效,你也可以完全Override并使用Animation等。
### 小结 ###
本文介绍了怎样为View/ViewModel构建自定义的生命周期,MonoBehaviour 虽然有自己的生命周期,但不够细腻,我们完全可以扩展自己的生命周期,实现对需求的定制。
源代码托管在Github上,[点击此了解](https://github.com/MEyes/uMVVM)
你也可以从以下链接获取更多有关Unity 3D Framework的设计:
[Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 1)](http://www.cnblogs.com/OceanEyes/p/unity3d_framework_designing_get_started_with_mvvm_part1.html)
[Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 2)](http://www.cnblogs.com/OceanEyes/p/unity3d_framework_designing_get_started_with_mvvm_part2.html)
[Unity 3D Framework Designing(2)——使用中介者模式解耦ViewModel之间通信](http://www.cnblogs.com/OceanEyes/p/using_message_aggregator_mediator_communication_between_viewmodels.html)
[Unity 3D Framework Designing(3)——构建View和ViewModel的生命周期](http://www.cnblogs.com/OceanEyes/p/view_viewmodel_lifecycle.html)
Unity 3D Framework Designing(3)——构建View和ViewModel的生命周期的更多相关文章
- Unity应用架构设计(3)——构建View和ViewModel的生命周期
对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者在各个阶段 ...
- Unity 3D Framework Designing(9)——构建统一的 Repository
谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化.Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化 ...
- Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 2)
MVVM回顾 经过上一篇文章的介绍,相信你对 MVVM的设计思想有所了解.MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在.View只关心怎样渲染,而ViewModel只 ...
- Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 1)
初识 MVVM 谈起 MVVM 设计模式,可能第一映像你会想到 WPF/Sliverlight,他们提供了的数据绑定(Data Binding),命令(Command)等功能,这让 MVVM 模式得到 ...
- Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 1)
『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...
- Unity 3D Framework Designing(6)——设计动态数据集合ObservableList
什么是 『动态数据集合』 ?简而言之,就是当集合添加.删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面.有经验的程序员脑海里迸出的第一个词就是 ObservableCollection.没 ...
- Unity 3D Framework Designing(7)——IoC工厂理念先行
一谈到 『IoC』,有经验的程序员马上会联想到控制反转,将创建对象的责任反转给工厂.IoC是依赖注入 『DI』 的核心,大名鼎鼎的Spring框架就是一个非常卓越的的控制反转.依赖注入框架.遗憾的是, ...
- Unity 3D Framework Designing(2)——使用中介者模式解耦ViewModel之间通信
当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子View(视图),或者子Component(组件).越是复杂的页面,被切割出来的子模块就越多,子模块 ...
- Unity 3D Framework Designing(5)——ViewModel之间如何共享数据
对于客户端应用程序而言,单页应用程序(Single Page Application)是最常见的表现形式.有经验的开发人员往往会把一个View分解多个SubView.那么,如何在多个SubView之间 ...
随机推荐
- mysql学习之权限管理
数据库权限的意义: 为了保证数据库中的业务数据不被非授权的用户非法窃取,需要对数据库的访问者进行各种限制,而数据库安全性控制措施主要有这三种,第一种用户身份鉴别,手段可以是口令,磁卡,指纹等技术,只有 ...
- tableView的编辑
首先记住声明编辑样式的属性 UITableViewCellEditingStyle 和四个步骤 第一步:让tableView处于编辑状态 [self.rootView.tabView setEdit ...
- c++ 继承类强制转换时的虚函数表工作原理
本文通过简单例子说明子类之间发生强制转换时虚函数如何调用,旨在对c++继承中的虚函数表的作用机制有更深入的理解. #include<iostream> using namespace st ...
- mybatis入门-第一个程序
今天,我们就一起来完成mybatis的第一个小demo,使用mybatis对我们的数据库进行一个小小的操作. 需求 根据用户id查询用户的信息. 环境搭建 java环境:jdk1.7版本 开发工具:e ...
- IP查询接口1
新浪的:http://counter.sina.com.cn/ip?ip=IP地址返回Js数据,感觉不是很精确,可以把问号后面的去掉,直接返回本机对应的IP所在地http://www.yodao.co ...
- python抓取NBA现役球员基本信息数据
链接:http://china.nba.com/playerindex/ 所需获取JSON数据页面链接:http://china.nba.com/static/data/league/playerli ...
- vue实现图书管理demo
年后公司的项目要求用到vue.js知识,我angular没有学,node.js和react也只是了解了一点点,所以学起来比较困难.如果你想学vue.js的知识,推荐网址:http://vuejs.or ...
- 在java中的Try Catch块-------------异常处理(2)
1. Try块是什么? Try块是一块可能产生异常的代码块,一个Try块可能跟着Catch块或者Finally块,或者两者. Try块的语义: try{ //statements that may c ...
- HTML5拖放事件-上传图片预览功能
主要用到的知识点有dataTransfer对象和FileReader(读取文件信息) 1.创建简单的HTML标签: <body> <div id="box"> ...
- Sicily 1151 魔板
Constraints Time Limit: 1 secs, Memory Limit: 32 MB , Special Judge Description 魔板由8个大小相同方块组成,分别用涂上不 ...