刘 瑞,刘晓燕,吉春山
(昆明理工大学 信息工程与自动化学院,云南 昆明 650504)
随着智能手机的普及,人们对移动用户体验的用户界面(UI)需求质量越来越高,这意味着不仅要提升移动用户界面的流畅性,更要提高UI的渲染程度,绚丽的UI更能吸引用户的眼球。在移动应用软件开发方面,许多软件公司都需要开发Android、iOS等平台的App,来满足不同终端用户的需求,延长了软件的开发周期。与此同时,移动开发中的动画和手势等技术时常成为开发人员的难题。
模型驱动构架(MDA)是一种用于应用系统开发的软件设计方法,可以用来创建良好的设计,应付多样化的实现技术,延长软件的生命周期,其关注的焦点是从代码上升到高度抽象的模型,而模型的构建通过建模语言对PIM进行建模,然后按照定义的映射规则来完成PIM到PSM的模型转换,最终实现PSM模型到目标代码的自动或半自动转换。
目前,国外已有研究人员将模型用在移动开发的设计上。Marco Brambilla等[1]提出了一种基于IFML标准的模型驱动的移动应用开发方法,对移动应用进行交互流建模语言的扩展,并设计基于Apache框架优化的HTML5、CSS和JavaScript开发跨平台移动应用程序的自动代码生成器。Roberto Acerbis等[2]对IFML扩展为Mobile IFML,并分析了基于IFML移动扩展版的模型驱动开发工具WebRatio Mobile Platform;此外,在会议论文中提出的WebRatio工具用于web和移动应用程序的模型驱动开发,基于IFML的两个扩展版本,该工具在应用程序的领域模型和用户交互模型的规范方面支持着开发人员的建模,并且具有模型检查和完整代码生成功能,可生成Web和跨平台的移动应用程序[3]。Carlo Bernaschina等[4]给出了交互流建模语言语义的形式化描述,规范了交互式应用程序的前端,并将定义的语义映射在一个在线模型驱动的开发环境中,通过仿真分析了IFML规范的行为,以及为移动App和基于web的应用程序生成代码。Yassine Rhazali等[5]提出了一种计算无关模型(Computational Independent Model,CIM)向基于web的PIM的模型转换方法,定义相应的规则构建CIM的级别,通过SoaML和IFML的建模,将PIM级别定向到web视图,最终转换到PSM。
国内对于IFML的研究始于2016年初。刘洪星教授等[6]重点研究用户界面的抽象建模,参考IFML规范,定义用户界面概念元模型,并实现该元模型具有实用性的用户界面概念建模工具。张天等[7-8]在其申请的专利中阐述了一种通过IFML建模,映射到Android和iOS平台上的方法。陆一飞等[9]在安卓应用上对IFML进行了扩展,提高其可用性和在安卓应用上的适用性,并对IFML模型进行了形式化定义,减少开发者在对安卓应用设计时存在的二义性,阐述了移动用户界面的结构以及其工作流的传递,并基于模型的测试方法进行了验证,验证了设计和实现所具有的一致性,以及在其过程中如何避免测试用例重复编写的有效性。王诗宇[10]在Mobile IFML的基础上改进,定义了一种移动用户界面概念建模语言,采用类图形式定义移动用户界面概念建模语言的元模型,采用OCL语言定义完整性约束,研究了源模型移动用户界面概念元素到Android平台目标模型的映射规则,并对映射规则作了形式化定义,并使用Acceleo工具的模板半自动地生成Android平台的目标代码。
然而,这些建模方法的设计大多是直接针对单一平台的移动应用,IFML的扩展也大多是基于视图容器和视图组件的扩展,较少考虑到前端UI的渲染问题。前端是跟用户联系最紧密的部分,良好的设计直接影响着用户体验。Flutter于2018年世界移动大会上公布,它有一套自己的代码库用来开发Android和iOS,其运行效率可以跟原生App相媲美。在Android、iOS等平台上,Flutter以60帧/秒的速度对UI持续渲染,对动画和手势等有很强大的API来支持。因此,为了设计出更加绚丽的前端界面,本文将研究基于IFML面向Flutter的建模方法及模型转换。
1.1.1 交互流建模语言
交互流建模语言(IFML)支持对在台式机、笔记本电脑、手机和平板电脑等系统上访问或部署的应用程序的图形用户界面进行独立于平台的描述[11]。设计者使用IFML建模有利于解决以下几个关于用户界面交互的问题:
(a)视图部分可划分为独立的可视化单元,这些单元可以同时显示,也可以互斥显示,还可以分层嵌套。
(b)视图的内容,不管是从服务器发送给用户的数据,还是从用户输入反馈给服务器的数据。
(c)控制用户与应用程序的交互。
(d)操作用户想要触发的行为事件。
(e)用户的交互和操作对用户界面的影响。
(f)用户界面元素和触发的行为事件之间的参数绑定。
1.1.2 Flutter简介
Flutter是谷歌新推出的一套跨平台、开源的UI框架,同时支持iOS、Android系统的开发,并且是新操作系统Fuchsia(由Google公司开发的继Android和Chrome OS之后的第三个操作系统)的默认开发套件[12]。Flutter的优势主要有以下几个方面[13]:
(a)Flutter有一套自己的代码库用来同时开发Android和iOS,并且开发出来的运行效率可以跟原生App相媲美,大大缩短了开发的周期,降低了消耗的资源和维护的成本。
(b)具有良好的跨平台特性,可以在MacOS、Windows、Linux、Android、iOS等操作系统上运行,甚至是嵌入式开发,从而降低开发成本。
(c)致力于提升用户体验,通过“自绘UI+原生系统”以60帧/秒的速度对UI持续渲染,其动画的流畅性已经达到了原生动画的效果,官方宣称目标是以120帧/秒的速率对界面进行渲染,超过原生应用的性能。
(d)在Android、iOS等平台上,Flutter支持程序的热重载(指开发人员可以立刻看到开发过程中App状态的更改,不用等待程序的重新编译),提高了开发效率。
(e)组件采用现代响应式框架的开发思路,对2D、动画、手势和效果等有很强大的API支持。
(f)通过Flutter的插件可以访问本地平台的API,如导航、多媒体、电量等,重用现有的Java、Swift、Objective C、C++等代码,并在iOS和Android上访问原生特性和软件开发工具包(SDK)。
1.2.1 抽象语法
对IFML面向Flutter平台的动画扩展,有动画特征(Animatable)、动画控制器(AnimationController)、动画状态监听器(AnimationStatusListener)、补间动画(Tween)、曲线动画(Curve)、英雄动画(Hero)等,如图1为动画元素的类图表示。
图1 动画元素的类图表示
IFMLM是IFML的顶层模型,直接或间接包含其它所有模型,可形式化表示为Model=
Animation(动画),判断当前动画状态的开始、停止、移动、前进、反向等,可形式化表示为Model=
Animatable(动画特征),控制动画的类型值,如平移动画中的坐标值以及颜色动画的色值变化等,可形式化表示为Model=
AnimationController(动画控制器),会在动画的每一帧,就生成一个新的值,即在给定的时间段内线性的生成默认区间为0.0到1.0的数字,还可控制渐变、位移、缩放等基础动画的交错显示,可形式化表示为Model=
AnimationStatusListener(动画状态监听器),管理动画状态每一帧的变化,可形式化表示为Model=
Tween(补间动画)指做Flash动画时,在两个关键帧中间需要做补间动画,才能实现图画的运动,主要用于构建UI的动画值在不同的范围或不同的数据类型,可形式化表示为Model=
Curve(曲线动画)用来描述动画的线性或非线性过程,其动画过程可以是匀速的、加速的或先加速后减速等,可形式化表示为Model=
Hero(英雄动画),用于在页面跳转时做出流畅的转场动画,可形式化表示为Model=
1.2.2 具体语法
主要介绍IFML模型中常用元素的样式及其内容,便于之后IFML的建模。IFML建模核心元素主要有页面(Page)、视图组件(View Component)、选择事件(Select Event)、行为(Action)、导航流(Navigation Flow)。其中,页面显示内容和支持交互;视图组件显示内容或接受输入的接口元素;选择事件表示用户界面中单个选项选择的事件;行为由事件触发的一段业务逻辑;导航流更新视图中的接口元素或触发由事件引起的操作。
模型转换是按照映射规则的定义从源模型到目标模型的自动或半自动的生成,而变换规则描述了用源语言表述的模型如何变换为用目标语言表述的模型。其中,模型到模型的转换主要由以下构成:
(a)计算无关模型(Computational Independent Model,CIM)到PIM,根据需求分析得到的业务模型转换为平台独立模型。
(b)PIM到PSM,是将平台独立的模型转换为平台相关模型,即通过映射规则,将源模型生成具体平台的目标模型。
(c)PSM到代码,指从平台相关模型自动或半自动地生成目标平台代码的过程。
IFML模型与Flutter平台界面组件的对应关系及其说明见表1。
表1 IFML模型与Flutter组件对应关系及说明
IFML模型是对各个组件抽象得到的一类模型,如ListView和GridView抽象为List,忽略了列表具体如何布局、划分等问题,不考虑组件的具体位置,而是通过IFML模型与IFML模型之间的嵌套、平行关系实现组件之间的位置关系。然后根据IFML模型类型,并在实现阶段填充与相对应的组件,进而实现组件的整体布局。
映射规则除了用于PSM的建模之外,更重要的是还可以把模型中的元素映射为目标代码中的具体元素,它是模型转换的前提[14]。以动画模型为例,IFML中的Animation模型到Fluteert中的Animation模型的映射规则如下[15]:
映射规则描述:属性AnimationStatusListener用于动画状态的监听,AnimationController为动画控制器,Tween为补间动画,Curve可以设置整个动画的变化过程。其中,dismissed表示动画结束并停在开始处,completed表示动画结束并停在末尾处,setState负责刷新UI,forward负责启动动画并正向执行,reverse方法负责动画的反向执行;IntTween为int类型的动画,ColorTween为颜色渐变动画,RectTween为圆角矩形动画;linear为匀速、decelerate为匀减速、ease为先加速后减速、easeIn为先慢后快、easeOut为先快后慢、easeInOut为先慢再加速至变快。每个IFML动画都被变换成一个Flutter动画,每个IFML动画关联都被变换成一个Flutter动画关联,每个IFML的动画属性都被变换成一个Flutter的动画属性。
映射规则示例如下:
Transformation AnimationToAnimation(IFML,Flutter){
params
attribute_1:Widget="AnimationStatusListener";
attribute_2:Widget="AnimationController";
attribute_3:Widget="Tween";
attribute_4:Widget="Curve";
source
animation:IFML::IFMLAnimation;
ifmlAssociationEnd_Animation:IFML:AssociationEnd_Animation;
ifmlAttribute:IFML::AnimationAttribute;
target
animation:Flutter::FlutterAnimation;
flutterAssociationEnd_Animation:Flutter:FlutterAssociationEnd_Animation;
attribute:Flutter::AnimationAttribute;
source condition
Animation.type=Animation and
ifmlAssociationEnd_Animation.association.oclIsTypeOf(Association);
target condition
Animation.type=Widget and
AnimationStatusListener.name=attributeName_1.concat(Animation.name)and
AnimationStatusListener.parameters ->exists(p丨
p.name=completed丨dismissed丨setState()and
p.type=Boolean)and
AnimationController.name=attributeName_2.concat(Animation.name)and
AnimationController.parameters->exists(p丨
p.name=reverse()丨forward()and
p.type=Animation.type)and
Tween.name=attributeName_3.concat(Animation.name)and
Tween.parameters->exists(p丨
p.name=IntTween丨ColorTween丨RectTween and
p.type=Animation.type)and
Curve.name=attributeName_4.concat(Animation.name)and
Curve.parameters->exists(p丨
p.name=linear丨decelerate丨ease丨easeIn丨easeOut丨easeInOut and
p.type=Animation.type);
unbidirectional;
mapping
ifmlAnimation.name<~>flutterAnimation.name;
ifmlAnimation.type<~>flutterAnimation.type;
ifmlAssociationEnd_Animation:name<~>flutterAssociationEnd_Animation:name;
IFML_Animation->forAll(IA丨Flutter_Animation->exists(FA丨IA<~>FA));
}
转换算法的转换过程为:首先读取模型和映射规则,解析该模型获取模型元素,然后根据对应的映射规则进行转换,最终生成目标代码。转换算法的基本步骤如下:
(1)对XML格式的模型文件进行解析,获取各个模型元素组成的节点树;
(2)针对各个模型元素,生成该节点ClassName为文件名称的Dart文件;
(3)对模型元素的子节点转换;
(4)根据映射规则,在得到的目标类的基础上,添加相关代码细节信息。
模型元素对应的是目标代码中的类对象,模型元素的子节点对应的是目标代码中的继承关系、属性、方法等。转换算法根据模型元素之间的逻辑关系来生成代码中的各个模块,使代码中的各个模块之间的关系和模型中的关系保持一致,确保模型向目标代码的整体转换。经过转换得到的目标代码,可以构建出基本的移动用户界面,然后通过对Flutter组件的添加和调整,生成最终的目标代码。
主要采用可以与人进行动画交互的登录界面进行说明,在该系统中默认已经注册了账号,需要实现的功能为交互式动画登录。其中,用户登录界面主要包含以下5种动画交互:
(a)无任何操作时的交互动画;
(b)在账号输入框中输入时的交互动画;
(c)在密码输入框中输入时的交互动画;
(d)登录失败时的交互动画;
(e)登录成功时的交互动画。
在对交互式动画登录界面分析后,使用IFML进行PIM建模,它对Flutter开发应用程序,在设计方面提供可视化的帮助,如界面的组成、交互。所以,本文需要通过ACERBIS[17]建模工具进行PIM建模。如图2所示为用IFML建立可以与人进行动画交互的登录界面的PIM。
图2 界面动画的PIM
在图2中显示了可以与人进行动画交互的登录界面的PIM。该模型的动画交互过程为:当用户无操作时触发无操作事件,导航流从视图容器指向无操作时的行为,随后导航流指向视图容器的眨眼睛动画组件;当用户触摸账号输入框并输入信息时触发用户输入账号事件,导航流从视图容器指向用户输入账号的行为,随后导航流指向视图容器的向下看动画组件;当用户触摸密码输入框并输入信息时触发用户输入密码事件,导航流从视图容器指向用户输入密码的行为,随后导航流指向视图容器的捂眼睛动画组件;当用户登录失败时触发用户登录失败事件,导航流从视图容器指向登录失败的行为,随后导航流指向视图容器的难过表情动画组件和账号或密码输入错误的提示信息组件;当用户登录成功时触发用户登录成功事件,导航流从视图容器指向登录成功的行为,随后导航流指向视图容器的高兴表情动画组件。
本文采用ANISZCZYK模型转换工具[18],通过IFML模型到Flutter平台的映射规则,来完成模型到模型的转换。如图3所示,按照2.3节给出的映射规则实现交互动画PSM的转换。
图3 动画构造过程的PSM
在该动画的构造过程PSM中,State经历了创建、重绘动画、销毁的整个生命周期,而监听器负责监听动画的状态,动画的状态通过AnimationStatus的completed和dismissed两种属性来判断动画是否结束,然后将信息传递给动画控制器,动画控制器通过forward()和reverse()方法来实现图片的正向和反向播放,并通过forward()方法用来启动动画;在Animation中的addListener()和addStatusListener()方法用来监听动画每一帧的变化动画状态的变化,从而实现动画的交互。
根据需求,分析对交互式动画登录界面进行总体结构设计,当用户无操作时,Flutter通过内部计时器控制动画熊每秒钟的时间间隔眨1次或2次眼睛,同时伴随着动画熊身体的略微晃动;当用户触摸账号输入框并输入信息时,动画熊会低下头并看向输入框,同时伴随着用户输入信息的长度而略微转动头部;当用户触摸密码输入框并输入信息时,动画熊会用双手蒙上眼睛;当用户登录失败时,动画熊会做出难过的表情;当用户登录成功时,动画熊会做出高兴的表情。
本节将运用在1.2节中的面向Fluttet平台的IFML扩展,对交互式动画登录界面建立PIM模型,增加应用程序的交互性;根据2.3节的映射规则,利用Eclipse EMF工具将PIM转换为PSM;最后,根据映射规则编写模板,将模板和PSM输入到Acceleo[19]平台中的代码生成器生成目标代码,其中,代码生成器对应转换算法,模板对应映射规则,同时模板是目标代码的源,可以看作是目标代码的原型,与目标代码相似度较高,可读性较强[20]。交互动画构造过程中的TweenAnimationState模板如图4所示。
在该模板中,主要体现类的继承关系、属性引用关系以及所拥有或继承的方法;将图3中的交互动画构造过程的PSM和上面的tweenAnimationState模板输入到Acceleo工具中可以生成TweenAnimationState目标代码,其中,TweenAnimationState类继承State类,引用AnimationController类和Animation类作为属性,并覆盖State类中的方法。本文以TweenAnimationState类中较为典型的initState()方法为例,通过Acceleo工具生成的TweenAnimationState目标代码如图5所示。
图5 TweenAnimationState目标代码
如图6所示为App登录界面的交互动画,在图中可以看到该登录页面实现了3.1节中的需求要素。由此说明本文对移动用户界面建模及模型转换成功实现。
图6 App登录界面的交互动画
随着移动应用的迅速发展,移动应用企业之间的竞争逐渐加剧,软件开发的规模和复杂性也在同步上升。为了契合广大用户手机的不同操作系统,企业往往需要同时开发Android和iOS版的App,同时使用绚丽的UI吸引客户。为此,本文在模型驱动的基础上,基于IFML面向具有良好跨平台性的Flutter进行动画和手势的扩展,对扩展的IFML模型进行形式化定义,并设计了PIM向PSM转换的映射规则。随后,通过对交互动画的案例分析验证了该方法的可行性和有效性,可以为移动用户提供绚丽的前端界面。