Dorothy Xml编写UI 2

  使用了Dorothy Xml编写界面以后,接下来要解决的问题是,为Xml中定义的纯展示界面增加界面逻辑。我们可以使用Dorothy的class类的机制,写一个继承Xml界面组件的带有界面处理逻辑的新的类。比如我们有一个按钮的Xml组件。

<!-- ButtonView.xml -->
<!-- params: X, Y, Radius, Text, FontSize -->
<MenuItem Name="menuItem" X="{ x }" Y="{ y }" Width="{ radius*2 }" Height="{ radius*2 }">
	<Action>
		<Opacity Name="fadeIn" Time="0" Alpha="1"/>
		<Opacity Name="fadeOut" Time="0.5" Alpha="0.4"/>
	</Action>

	<DrawNode X="{ radius }" Y="{ radius }" Opacity="0.4">
		<Dot Radius="{ radius }" Color="0xff00ffff"/>
	</DrawNode>
	<LabelTTF Name="label" X="{ radius }" Y="{ radius }" Text="{ text }"
			FontName="Arial" FontSize="{ fontSize }" Ref="True"/>

	<Slot Name="TapBegan">
		menuItem:perform(fadeIn)
	</Slot>
	<Slot Name="TapEnded">
		menuItem:perform(fadeOut)
	</Slot>
</MenuItem>

  注意我们通过设置Name和Ref属性来导出了访问LabelTTF的接口label。然后我们写一个类来继承这个组件并添加一些业务逻辑:

-- Button.lua
Dorothy()
local ButtonView = require("ButtonView")

-- params: x, y, radius, text, fontSize
local Button = Class(
{
	-- 继承C++对象的方法
	__partial = function(self, args)
		return ButtonView(args)
	end,

	-- 构造函数
	__init = function(self, args)
		self._text = args.text -- 存储按钮上的文本

		self._clickCount = 0 -- 记录按钮被点击次数
		
		self:slot("Tapped",function() -- 监听点击事件
			self._clickCount = self._clickCount + 1 -- 点击次数 +1
		end)
	end,

	-- 添加text属性
	text = property(
		function(self) -- getter
			return self._text
		end,
		function(self, value) -- setter
			self._text = value
			self.label.text = value -- 获取并设置label组件的text
		end),

	-- 添加clickCount属性
	clickCount = property(
		function(self) -- getter only
			return self._clickCount -- 获取点击次数
		end),

	-- 添加clearClickCount方法
	clearClickCount = function(self) -- 点击次数置为0
		self._clickCount = 0
	end,
})

return Button

  我们给按钮增加的业务逻辑主要是一个统计点击次数的功能,一个获取点击次数的接口clickCount,还有一个直接设置按钮文本的接口text。接下来使用这个扩展业务逻辑了的按钮。

<!-- MainSceneView.xml -->
<Scene>
	<Import Module="Button"/><!-- 直接在Xml中引用 -->

	<Menu X="100" Y="100" Width="50" Height="50">
		<Button Name="button" X="25" Y="25" Radius="25" Text="Click"
			FontSize="14" Ref="True"/><!-- 创建并导出对象 -->
	</Menu>
</Scene>

  接下来给MainScene.xml也添加业务逻辑。

-- MainScene.lua
Dorothy()
local class, property = unpack(require("class"))
local MainSceneView = require("MainSceneView")

local MainScene = class(
{
	__partial = function(self, args)
		return MainSceneView(args)
	end,

	__init = function(self, args)
		self.button.text = "Button"

		self.button:slots("Tapped",function(button)
			print("Button click count:", button.clickCount)
		end)
	end,
})

return MainScene

-- main.lua
local MainScene = require("MainScene")
CCDirector:run(MainScene())

  这样我们的界面开发的程序逻辑组织就比较完善了。用Dorothy Xml来管理界面外观,然后在Lua类中写界面逻辑。现在纯粹的界面外观和带业务逻辑的界面就可以分别独立被引用了。

Moonscript

  有了Dorothy Xml简化界面代码的编写,我们更进一步地引入了Moonscript的新语言,Moonscript是一门编译成Lua运行的语言,所以可以和Lua无缝结合使用。它的最大的特性就是省代码,省代码的好处并不是减少键盘敲击次数,而是提高代码文本的信息量并提高代码的可维护性。当然这也带来一个很大缺点就像是阅读和编写文言文那样,如果不懂文字中相关的很多梗,光凭简练的几个字很难让人读得明白,下面就来看一下Moonscript怎么写业务逻辑吧,比如前文的代码可以写成:

-- Button.moon
Dorothy!
Class, property = unpack require "class" -- class是Moonscript的关键字,所以这里改为大写
ButtonView = require "ButtonView"

-- params: x, y, radius, text, fontSize
Class
	__partial: (args)=> ButtonView args
	__init: (args)=>
		@_text = args.text
		@_clickCount = 0
		@\slots "Tapped",-> @_clickCount += 1

	text: property => @_text,
		(value)=>
			@_text = value
			@label.text = value

	clickCount: property => @_clickCount

	clearClickCount: => @_clickCount = 0

-- MainScene.moon
Dorothy!
Class, property = unpack require "class"
MainSceneView = require "MainSceneView"

Class
	__partial: (args)=> MainSceneView args
	__init: (args)=>
		@button.text = "Button"
		@button\slots "Tapped",(button)->
			print "Button click count:", button.clickCount

-- main.moon
MainScene = require "MainScene"
CCDirector\run MainScene!

  比前文的代码要简练了很多,但功能是完全相同的。实际上这段Moon代码编译成Lua以后和上面的Lua代码几乎是一模一样的,所以普通逻辑的代码不用担心性能降低的问题。Moonscript使用了Python的缩进控制代码块的方式,以及很多和Python相似的语法功能,具体语言的特性以后我还会作详细介绍。今天还想说的是Moon代码的编译运行方法有两种,一种是在Lua代码中引入代码的实时Loader,然后就可以直接用require来实时编译并执行代码,另一种方式是把Moon代码先预编译成Lua代码,然后直接加载Lua代码文件。在Dorothy中,实时编译执行Moon代码还可以通过替换debug.traceback来获取Moon代码运行时的错误信息以及错误出现的位置。此外,目前Moon还没有编辑器支持代码补全,对各种Dorothy API的补全目前还做不到,所以Dorothy目前只添加了带Moon高亮和运行环境SciTE编辑器,编码起来目前还是不太方便,但是之后我会开发一些相关的辅助工具。

标题目录