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之间 ...
随机推荐
- redis集群原理
redis是单线程,但是一般的作为缓存使用的话,redis足够了,因为它的读写速度太快了. 官方的一个简单测试: 测试完成了50个并发执行100000个请求. 设置和获取的值是一个256字节字符串 ...
- MongoDB学习总结(一) —— Windows平台下安装
> 基本概念 MongoDB是一个基于分布式文件存储的开源数据库系统,皆在为WEB应用提供可扩展的高性能数据存储解决方案.MongoDB将数据存储为一个文档,数据结构由键值key=>val ...
- Java Web(一) Servlet详解!!
这篇文章到上一篇,距离的有点遥远呀,隔了大概有两个月把,中间在家过了个年,哈哈~ 现在重新开始拾起,最近在看一本个人觉得很棒的书,<Java Web 整合开发王者归来>,现在写的这一系列基 ...
- (一) 从Angular1到Angular2的杂谈
使用了angular1一年下来,完成了若干项目,承蒙此框架的强大带来了不算差的项目编写体验,但1.*版本的angular,确实是有厉害的地方也有其尴尬的地方,包括较多数据的渲染的性能问题,还有就是可能 ...
- warshall、
#include<iostream> int mian() { ][],b[][],c[][]; int i,j,k; cout<<"input the Boolea ...
- [转]ios 数据的传递
情景1: A-->B 需要把数据传递到B里 代码: // 跳转 -- 执行login2contacts这个segue [self performSegueWithIdentifier:@&qu ...
- Animate自定义动画
在jQuery中出了基本的动画之外,还有用户 可以自定义的函数,Animate() 用于创建自定义动画的函数. apI上指出: 这个函数的关键在于指定动画形式及结果样式属性对象.这个对象中每个属性都表 ...
- 什么是Git?
其实我在写这篇随笔的时候连Git是什么都不知道,只是听说过,也注册了一个GitHub的账号,但并不会玩. 我也是查看了半天的网页才明白一个大概,但我觉得以后肯定会经常用到它. 简单的来说, Git 是 ...
- keepalived配置文件
1. 查看进程 ps aux | grep keepalived ,其输出为: [root@lvs-m ~]# ps aux| grep keepalived |grep -v greproot 21 ...
- Regular Expression(正则表达式)之邮箱验证
正则表达式(regular expression, 常常缩写为RegExp) 是一种用特殊符号编写的模式,描述一个或多个文本字符串.使用正则表达式匹配文本的模式,这样脚本就可以轻松的识别和操作文本.其 ...