引擎内置的 6 种动画 --PosChangeAnimation 平移 local ani = XLGetObject("Xunlei.UIEngine.AnimationFactory"):CreateAnimation("PosChangeAnimation") ani:BindObj(imageObj) ani:SetTotalTime(5000) ani:SetLoop(true) ani:SetKeyFramePos(100,0,200,0) imageObj:GetOwner():AddAnimation(ani) ani:Resume() --AngleChangeAnimation 旋转 local ani = XLGetObject("Xunlei.UIEngine.AnimationFactory"):CreateAnimation("AngleChangeAnimation") ani:BindObj(imageObj) ani:SetKeyFrameAngle(0,0,0,0,0,360) ani:SetTotalTime(5000) ani:SetLoop(true) ani:SetBlendMode("AntiAlias") imageObj:GetOwner():AddAnimation(ani) ani:Resume() --AlphaChangeAnimation 透明度 local ani = XLGetObject("Xunlei.UIEngine.AnimationFactory"):CreateAnimation("AlphaChangeAnimation") ani:BindRenderObj(imageObj) ani:SetTotalTime(2000) ani:SetKeyFrameAlpha(255,0) imageObj:GetOwner():AddAnimation(ani) ani:Resume() --SeqFrameAnimation 序列帧 local ani = XLGetObject("Xunlei.UIEngine.AnimationFactory"):CreateAnimation("SeqFrameAnimation") ani:BindImageObj(imageObj) ani:SetTotalTime(2000) ani:SetLoop(true) ani:SetResID("ImageSeq.BoltTest.SeqAni") imageObj:GetOwner():AddAnimation(ani) ani:Resume() --TurnObjectAnimation 对象1旋转到对象2 local imageObj2 = ctrlObj:GetControlObject("TestAni2.Texture") local ani = XLGetObject("Xunlei.UIEngine.AnimationFactory"):CreateAnimation("TurnObjectAnimation") ani:BindRenderObj(imageObj1,imageObj2) ani:SetFlag("RoundY") ani:SetTotalTime("500") imageObj1:GetOwner():AddAnimation(ani) ani:Resume() --MaskChangeAnimation MaskObject 位置改变 local maskObj = ctrlObj:GetControlObject("MaskAni.Mask") local uiObject = ctrlObj:GetControlObject("MaskAniBkg.Texture") local ani = XLGetObject("Xunlei.UIEngine.AnimationFactory"):CreateAnimation("MaskChangeAnimation") ani:BindMaskObj(maskObj) ani:SetMaskKeyFrame(0,0,80,80,0,-80,80,80) ani:SetLoop(true) ani:SetTotalTime(1000) maskObj:GetOwner():AddAnimation(ani) ani:Resume() MaskObject 的使用方法参考相关文档; 注意这里只调用了 BindMaskObj 而没有调用 BindTargetObj ,不知道为啥调用了 BindTargetObj 之后动画并不会被执行 注意:不知道为啥旋转动画不能在OnInitControl里面直接使用,需要用AsynCall调用才行: function OnInitControl(ctrlObj) local imageObj = ctrlObj:GetControlObject("TestAni.Image") AsynCall(function() -- 异步调用 -- AngleChangeAnimation 旋转 local rotateAni = XLGetObject("Xunlei.UIEngine.AnimationFactory"):CreateAnimation("AngleChangeAnimation") rotateAni:BindObj(imageObj) rotateAni:SetKeyFrameAngle(0,0,0,0,0,360) rotateAni:SetTotalTime(5000) rotateAni:SetLoop(false) rotateAni:SetBlendMode("AntiAlias") imageObj:GetOwner():AddAnimation(rotateAni) rotateAni:Resume() end) end 自定义动画: 在 xml 文件里定义动画模版: <animation_def class="BoltTest.ani"> <method_def> <Action file="MainWnd.xml.lua" func="BoltTestAni_Action"/> <BindObj file="MainWnd.xml.lua" func="BoltTestAni_BindObj"/> <GetBindObj file="MainWnd.xml.lua" func="BoltTestAni_GetBindObj" /> </method_def> </animation_def> 在 lua 文件里使用动画: function BoltTestAni_Action(aniSelf) local attr = aniSelf:GetAttribute() local bindObj = attr.BindObj if bindObj == nil then return end local totalTime = aniSelf:GetTotalTime() local runningTime = aniSelf:GetRuningTime() --[[ 按时间缩小 local progress = (totalTime - runningTime) / totalTime if progress < 0 then progress = 0 end local l,t,r,b = bindObj:GetObjPos() bindObj:SetObjPos(l,t,r,t+(b-t)*progress) --]] -- 按指定间隔切换图片 local frameTime = 1000 local progress = runningTime / frameTime + 1 if progress > 5 then progress = 5 elseif progress < 1 then progress = 1 end progress = math.floor(progress) bindObj:SetResID("Bitmap.BoltTest.SeqAni"..progress) end function BoltTestAni_BindObj(aniSelf, obj) local attr = aniSelf:GetAttribute() attr.BindObj = obj end function BoltTestAni_GetBindObj(aniSelf) local attr = aniSelf:GetAttribute() return attr.BindObj end 注意:XLUE 每隔 1/30 秒刷新一次界面,每次刷新时改变对象的状态,这是自定义动画的基本原理; Action 方法每隔 1/30 秒调用一次; BindObj 方法里通过 attr 表来保存要渲染的对象; GetRuningTime 方法获取动画的运行时间,因为是每隔 1/30 秒调用一次 Action 方法,所以 GetRuningTime 也是每隔 1/30 递增 动画的状态改变事件: -- state: 0 动画未绑定对象;1 动画准备就绪;2 动画正在执行;3 动画暂停; 4 动画结束 ani:AttachListener(true, function(aniSelf, oldState, newState) -- TODO end) 注意这里,如果设定动画 SetLoop(true) state 将在 2 和 4 之间转换; 对一个动画进行 Stop,state 变为 4 而不是 3;也就是动画结束而不是动画暂停; 对一个动画进行 Stop,再调用 resume 并不能够使暂停的动画重新开始; 对一个动画进行 Stop,该动画实例即失效,需要重新创建该动画才能使动画重新运行 同时执行多个动画: 将多个动画对象绑定到同一个 UIObject 上即可: -- PosChangeAnimation 平移 local ani = XLGetObject("Xunlei.UIEngine.AnimationFactory"):CreateAnimation("PosChangeAnimation") ani:BindObj(imageObj) ani:SetTotalTime(5000) ani:SetLoop(false) ani:SetKeyFramePos(100,0,200,0) imageObj:GetOwner():AddAnimation(ani) ani:Resume() --SeqFrameAnimation 序列帧 local ani = XLGetObject("Xunlei.UIEngine.AnimationFactory"):CreateAnimation("SeqFrameAnimation") ani:BindImageObj(imageObj) ani:SetTotalTime(2000) ani:SetLoop(true) ani:SetResID("ImageSeq.BoltTest.SeqAni") imageObj:GetOwner():AddAnimation(ani) ani:Resume() 注意这里,不知道为啥 AngleChangeAnimation 旋转动画跟 SeqFrameAnimation 序列帧动画不能一起用; 执行动画序列: local function StartAnimSequence(onFinish, ...) local function StartAnim(aniIndex) if arg[aniIndex] == nil then onFinish() return end arg[aniIndex]:AttachListener(true, function(aniSelf, oldState, newState) if newState == 4 then StartAnim(aniIndex + 1) end end) arg[aniIndex]:Resume() end StartAnim(1) end StartAnimSequence(function() return end, posAni, rotateAni) 尝试用这种方法封装一个执行动画序列的方法;发现不行,不知道为啥; 动画曲线: 在资源 xml 里定义 curve 资源,可使用 CurveTool 工具来定义: <curve id="Curve.BoltTest.MyAni" type="bspline"> <controlpoint tp="0.000000" sp="0.000000"/> <controlpoint tp="0.854396" sp="0.025281"/> <controlpoint tp="0.859890" sp="0.977528"/> <controlpoint tp="0.997253" sp="1.000000"/> </curve> 在自定义动画里通过 Curve:GetProgress(tp) 传入一个时间,获取对应的进度: local curve = aniSelf:GetCurve() local tp = runningTime / totalTime local progress = curve:GetProgress(tp) 利用这个 progress 来设定进度即可