解析BLOT例子——HelloBolt5

HelloBolt5:使用动画

作者:Tsukasa

     在HellohBolt5中,我们将在HelloBolt4的基础上加入两个很Cool的动画效果,让界面动起来:第一,在关机图标上,每隔5s将其变为另一个图标;第二,当点击关闭按钮时,星星图标在原位置上逐渐变大并消失,正中的HelloBolt文本向右“飞出”界面,之后程序退出。

    解析BLOT例子——HelloBolt5_第1张图片
   
  前面的教程中已经说过,Bolt在一个内置时钟的驱动下,每隔若干时间对对象树进行一次渲染,更新对象树上被改变部分的输出,并将渲染结果在容器窗口中显示,称为一帧。比如在前一帧渲染之后,将某个对象移动位置,那么在下一帧渲染时,Bolt会重新渲染对象树上该对象之前的位置部分和之后的位置部分,这样展示出来的界面就发生了变化。如果我们将改变某对象位置这个操作的时间延长,比如延长到100帧,指定对象的初始位置和结束位置,并按照一定的规则对中间每一帧的对象位置进行插值,那么在每一帧中,对象只会被移动一小段距离,渲染出来的结果也会发生相应微小的改变,这样在这段时间内的,视觉上,界面就会展示出对象从初始位置连续移动到结束位置的效果,这就是Bolt中关键帧动画的原理。我们称动画执行的这段时间为持续时间,动画中每一帧的时刻为运行时刻,依照动画改变属性的对象为动画的执行对象。
首先,让我们来看看退出程序时的动画是如何实现的。转到MainWnd.xml.lua中在close_btn_OnLButtonDown函数定义代码如下:
local aniFactory = XLGetObject("Xunlei.UIEngine.AnimationFactory")
     local alphaAni = aniFactory:CreateAnimation("AlphaChangeAnimation")
以上两行中,"Xunlei.UIEngine.AnimationFactory"标识的全局对象是Bolt用于创建动画对象的动画工厂对象, 在动画工厂对象上调用CreateAnimation接口创建指定类型的动画对象,可以创建的动画类型包括Bolt的内建动画(包括改变对象透明度的AlphaChangeAnimation,改变对象位置的PosChangeAnimation等)及在布局xml中自定义的动画类型。这里创建的是一个类型为AlphaChangeAnimation动画对象。

alphaAni:SetTotalTime(700)

alphaAni:SetKeyFrameAlpha(255,0)
以上两行,设置刚创建出来的动画对象的几个关键属性。SetTotalTime接口以ms为单位,指定动画的持续时间,对于改变对象透明度(alpha)的动画来说,要指定执行对象的初始和结束的透明度,通过调用SetKeyFrameAlpha接口来设置。这样这个动画就可以在700ms内将执行对象的透明度从全不透明(255)改变到全透明(0).

local owner = self:GetOwner()

         local icon = owner:GetUIObject("icon")
以上两行获取指向星星图标对象的引用。因为close_btn_OnLButtonDown的self参数指向的是关闭按钮逻对象,而星星图标对象与之在同一对象树之上,可以通过对象树的对象索引接口得到该对象,调用UIObject的GetOwner接口返回该对象所在的对象树对象,调用对象树的GetUIObject接口获取对象树上指定id的UIObject对象,这样我们就得到了需要的对象;

alphaAni:BindRenderObj(icon)

          owner:AddAnimation(alphaAni)
         alphaAni:Resume()

以上几行,用动画的BindRenderObj接口指定执行对象,调用AddAnimation接口将动画对象加入到对象树的正在运行动画列表中,只有加入到该列表中的动画对象才能在时钟的驱动下,更新动画的运行时刻,当到达持续时间时,该动画结束,同时被从列表中移除。最后调用Resume接口,指定动画开始执行。
        类似的创建并执行另外几个动画,注意这里有两个不同动画对象指定了同一个执行对象,在Bolt里这是允许的,前提是两个动画对象是作用于对象的不同属性之上的,比如这里一个动画对象改变透明度,另一个改变位置,如果两个动画对象都改变透明度,Bolt会按照一定的规则来解决两个动画对象的冲突。
     动画的引入让我们的交互逻辑产生了变化:不能在close_btn_OnLButtonDown事件中立刻退出应用程序了,要让HelloBolt在动画结束之后再退出。为了达到这个目的,我们需要为动画对象添加状态改变的响应函数, 动画状态改变响应函数的原型为function onStateChange(self,oldState,newState), self是指向状态改变的动画对象的引用,oldState 和 newState表示改变时的前状态和后状态, 动画的状态 是从0 到 4的整形, 当为4时标明动画已经执行完成,退出程序,代码如下所示:

if newState == 4 then

              os.exit()
     end

     之后调用动画对象上的AttachListener接口指定上面定义的函数作为动画对象的状态响应函数,代码如下:

posAni2:AttachListener(true,onAniFinish)

这样当posAni2动画对象执行完成时,程序退出。
 
     上面使用了Bolt的内建动画,已经可以满足大部分常用动画需求(内建动画手册),除此之外,Bolt还提供了自定义动画机制(自定义动画指南)。转到MainWnd.xml中,定义一个自定义动画,xml节点如下所示:
定义自定义动画要在布局xml中加入节点,其中class属性指定动画的类型名;在子节点中加入节点定义动画的行为, Action函数的原型为function Action(self), 当对象树在每帧中渲染的时候,都会调用该函数。在method_def节点中定义函数, 类似于在eventlist中定义event。比如 xxx func= yyy /> ,其中节点名指定函数名, 该函数名可以作为对象的方法直接调用, 比如HelloBolt.ani类型的对象a可以在lua中用a:Action()的方式调用Action。我们在这里使用Bolt中另一种定义方法或事件的方式: 直接在布局xml中定义方法, 格式如函数体 OnLButtonDown > 函数体,这种写法比较适合教学演示实例代码,不推荐在实际的工程开发中使用。Action函数的定义如下:

local attr = self:GetAttribute()

     local obj = attr.obj  
local runningTime = self:GetRuningTime()
以上三行中,调用GetRunningTime() 和 GetTotalTime()接口分别获取动画对象执行时刻和通过SetTotalTime()设置的持续时间, 通过这两个值可以自行计算自定义动画的进度。在自定义对象(自定义动画对象和自定义控件对象)上调用GetAttribute()方法获取绑定到该对象上的一个lua table实例,称为属性表。可以在属性表上之上加入任何lua 对象, 在自定义对象的生命周期里可以访问属性表。 虽然没有为自定义动画定义类似BindObject的方法, 但是自定义动画仍然可以在执行Action时通过属性表获取执行对象。在这个Action的定义中,每隔5000ms将执行对象展示的位图改变。

        定义好了自定义动画之后,要通过跟使用内置动画类似的流程来使用之,代码如下所示:

local aniFactory = XLGetObject("Xunlei.UIEngine.AnimationFactory")

     myAni = aniFactory:CreateAnimation("HelloBolt.ani")
     myAni:SetTotalTime(9999999)
     local aniAttr = myAni:GetAttribute()
     aniAttr.obj = newIcon
     owner:AddAnimation(myAni)
     myAni:Resume()

与创建Bolt内置动画基本相同,只是在调用CreateAnimation接口时传入自定义动画的类型名。对照自定义动画Action的定义,通过调用GetAttribute()接口获取属性表并在其中加入元素,将执行对象传入到Action定义中使用。


MainWnd.xml.lua中
--lua文件必须是UTF-8编码的(最好无BOM头)
function close_btn_OnLButtonDown(self)
	---创建内置动画的实例
	local aniFactory = XLGetObject("Xunlei.UIEngine.AnimationFactory") --Xunlei.UIEngine.AnimationFactory标识的全局对象是Bolt用于创建动画对象的动画工厂对象
	local alphaAni = aniFactory:CreateAnimation("AlphaChangeAnimation") --在动画工厂对象上调用CreateAnimation接口创建指定类型的动画对象
	alphaAni:SetTotalTime(700)  --一直运行的动画就是一个TotalTime很长的动画
	alphaAni:SetKeyFrameAlpha(255,0) --对于改变对象透明度(alpha)的动画来说,要指定执行对象的初始和结束的透明度,
	                                    --通过调用SetKeyFrameAlpha接口来设置。这样这个动画就可以在700ms内将执行对象的透明度从全不透明(255)改变到全透明(0). 
	local owner = self:GetOwner()
	local icon = owner:GetUIObject("icon") --以上两行获取指向星星图标对象的引用
	alphaAni:BindRenderObj(icon)  --用动画的BindRenderObj接口指定执行对象
	owner:AddAnimation(alphaAni) --调用AddAnimation接口将动画对象加入到对象树的正在运行动画列表中
	alphaAni:Resume() --最后调用Resume接口,指定动画开始执行。

	local key = owner:GetUIObject("key")  --先获取对象
	local posAni = aniFactory:CreateAnimation("PosChangeAnimation")
	posAni:SetTotalTime(700)
	posAni:SetKeyFrameRect(45,100,45+60,100+60,45+30,100+30,45+60-30-10,100+60-30-10)
      --SetKeyFrameRect方法设置对象开始位置和结束位置的left,top,right,bottom信息,对象的尺寸是随着参数变化。
	posAni:BindLayoutObj(icon) 
	owner:AddAnimation(posAni)
	posAni:Resume()
    
	--自定义动画
	local posAni3 = aniFactory:CreateAnimation("PosChangeAnimation")
	posAni3:SetTotalTime(1000)
	posAni3:SetKeyFramePos(150,80,600,80)
      --SetKeyFrameRect方法设置对象开始位置和结束位置的left,top,right,bottom信息,对象的尺寸是随着参数变化。
	posAni3:BindLayoutObj(key) 
	owner:AddAnimation(posAni3)
	posAni3:Resume()
	
	
	local alphaAni2 = aniFactory:CreateAnimation("AlphaChangeAnimation")
	alphaAni2:SetTotalTime(700)
	alphaAni2:SetKeyFrameAlpha(255,0)  --对于改变对象透明度(alpha)的动画来说,要指定执行对象的初始和结束的透明度,
	                                    --通过调用SetKeyFrameAlpha接口来设置。这样这个动画就可以在700ms内将执行对象的透明度从全不透明(255)改变到全透明(0). 
	local msg = owner:GetUIObject("msg")
	alphaAni2:BindRenderObj(msg)
	owner:AddAnimation(alphaAni2)
	alphaAni2:Resume()
	
	---定义动画结束的回调函数
	local function onAniFinish(self,oldState,newState)
		if newState == 4 then
		----os.exit 效果等同于windows的exit函数,不推荐实际应用中直接使用
			os.exit()
		end
	end

	local posAni2 = aniFactory:CreateAnimation("PosChangeAnimation")
	posAni2:SetTotalTime(800)
	posAni2:BindLayoutObj(msg)
	posAni2:SetKeyFramePos(135,100,135,500)
	--当动画结束后,应用程序才退出
	posAni2:AttachListener(true,onAniFinish) --AttachListener接口指定上面定义的函数作为动画对象的状态响应函数
	owner:AddAnimation(posAni2)
	posAni2:Resume()
end

function OnInitControl(self)
	local owner = self:GetOwner()
	
	--动态创建一个ImageObject,这个Object在XML里没定义
	local objFactory = XLGetObject("Xunlei.UIEngine.ObjectFactory")
	local newIcon = objFactory:CreateUIObject("icon2","ImageObject")
	local xarManager = XLGetObject("Xunlei.UIEngine.XARManager")
	newIcon:SetResProvider(xarManager)
	newIcon:SetObjPos(45,165,45+70,165+70)
	newIcon:SetResID("app.icon2")
	local function onClickIcon()
		XLMessageBox("Don't touch me!")
	end
	--绑定鼠标事件的响应函数到对象
	newIcon:AttachListener("OnLButtonDown",true,onClickIcon)
	self:AddChild(newIcon)
	
	--创建一个自定义动画,作用在刚刚动态创建的ImageObject上
	local aniFactory = XLGetObject("Xunlei.UIEngine.AnimationFactory") --Xunlei.UIEngine.AnimationFactory标识的全局对象是Bolt用于创建动画对象的动画工厂对象
	myAni = aniFactory:CreateAnimation("HelloBolt.ani") --在动画工厂对象上调用CreateAnimation接口创建指定类型的动画对象
	--一直运行的动画就是一个TotalTime很长的动画
	myAni:SetTotalTime(9999999) --SetTotalTime接口以ms为单位,指定动画的持续时间
	local aniAttr = myAni:GetAttribute()
	aniAttr.obj = newIcon
	owner:AddAnimation(myAni)
	myAni:Resume()
	
end

function MSG_OnMouseMove(self)
	self:SetTextFontResID ("msg.font.bold")
	self:SetCursorID ("IDC_HAND")
end

function MSG_OnMouseLeave(self)
	self:SetTextFontResID ("msg.font")
	self:SetCursorID ("IDC_ARROW")
end

MainWnd.xml中:




		
		
			--自定义动画,短函数可以直接在xml里写代码(正规开发不推荐)
			local arg={...}
			local self = arg[1]
			local attr = self:GetAttribute()
			local obj = attr.obj
			local runningTime = self:GetRuningTime() --调用GetRunningTime() 获取动画对象执行时刻 GetTotalTime() 通过SetTotalTime()设置的持续时间
			if runningTime%5000 > 2500 then
				obj:SetResID("app.icon2")
			else
				obj:SetResID("app.icon")
			end
			
			return 1
		
		
	


	
			-200
			-200
			2000
			2000
	

	
		
			0
			0
			429
			267
			
			app.bkg
			255
		
		
			
				
					135
					100
					250
					50
					Hello,Bolt!
					system.orange
					msg.font
						
				
					
					
				
			
			  
			    
				    150
					80
					128
					128
					key
					200	
				
			
			
			
				
					0
					0
					32
					father.width
					100
				
				
					
						
							
							father.width/2-86/2 
							8
							86
							24			
							Hello,Bolt!
							system.white
							default.font
						
					
			
				
			
			
			
				
					45
					100
					60
					60
					app.icon
					
					1
				
			
			
			
				
					178
					214
					80
					30
				
				
					
					
						
							0
							0
							father.width
							father.height
							button.normal
						
					
					
						
							0
							0
							father.width
							father.height
							default.font
							center
							center
							关闭
						
					
				
				
					
				
			
		
		
		
			
		
	

	

		 
			1
			Bolt
			1
			200 
			100
			
			429
			327
			0 
			0

			1000
			720
			
1
0 1 1 1 0 0 100 72 1000 720 1 30


你可能感兴趣的:(BOLT,action,class,animation,function,xml,file)