DirectUI通用动画框架

来源:互联网 发布:查看域名是否备案 编辑:程序博客网 时间:2024/05/24 16:15

        在编写VC界面时,编写动画比较困难,代码重用性不高。编写一个临时动画需要创建定时器或者线程来驱动改变渲染状态,来达到画面实时改变的目的。但是定时器和线程都是比较难以维护的,处理不好很容易造成资源浪费甚至程序崩溃。

         Skilla在上一周整理好了skillcore库,这一次又给它增添了通用动画框架。这个动画框架本身没有渲染功能,主要是提供动画的驱动事件,使用时需要自己去处理动画事件去完成动画渲染。该框架比较简单,动画由线程来驱动,下面展示一下具体的构成。


       根据动画的特点,就像播放动画片一样,Skilla把动画抽象成了一个动画基类BaseAnimation,里面包括动画的运行时间,运行状态,循环状态,正反序等等。使用时可以调用PlayAnimation,PauseAnimation,ResumeAnimation,StopAnimation等方法来控制动画的运行状态。动画本身还可以绑定动画监听器AnimationListener来触发动画状态改变时的事件,以方便处理。BaseAnimation本身是个抽象类,使用时需实现virtual bool FirstRun() = 0; virtual void Run() = 0; virtual bool LastRun() = 0;这三个接口,firstRun触发时,渲染动画的初始状态,lastRun触发时渲染动画的结束状态,Run触发时则根据runningTime这个时间轴属性来渲染动画每一帧的状态。为了方便使用Skilla实现了三个常用动画子类,PosChangeAnimation  AlphaChangeAnimation和SeqFrameAnimation,它们分别是位置改变动画,渐隐渐显(透明度改变)动画以及序列帧动画。关于使用方法在下面介绍。

      由于动画的生命周期难以管理,因为有的动画为临时动画,播放一次就再也不用了;而有的动画则需要重复使用,甚至绑定到控件上,和执行动画的控件同生共死。之所以出现这个问题就是因为把动画抽象成了类。这时候用指针来管理动画的生命周期明显是个坏主意,为了保证其通用性,我们采用动画工厂来管理动画的生命周期,创建动画时采用AnimationFactory动画工厂,操作现有动画时,使用AnimationFactory的FindAniamtion方法通过aniamtionName取到动画对象指针,删除动画同样要使用AnimationFactory通过animationName来删除。在应用程序退出时,需要AnimationFactory清理掉所有的剩余动画对象。

     下面以duilib界面库为例,看看具体如何使用的

class CloseAnimationListener : public AnimationListener{public:LRESULT OnStop(std::int64_t runningTime,std::int64_t totalTime,bool bReverse,bool bLoop){AnimationFactory::GetInstance()->DeleteAnimation(L"PosChange.CloseAni");DuiApplicationBase::GetInstance()->RequestQuit();return AnimationListener::OnStop(runningTime,totalTime,bReverse,bLoop);}};class AlphaChangeListener : public AnimationListener{public:LRESULT OnPlayEnd(std::int64_t runningTime,std::int64_t totalTime,bool bReverse,bool bLoop){BaseAnimation* p = AnimationFactory::GetInstance()->FindAnimation(L"AlphaChange.InitAni");p->SetReverse(!p->GetReverse());return 0;}};class CMainFrame : public WindowImplBase ,public IPosChangeAnimation,public ISeqFrameAnimation,public IAlphaChangeAnimation{public:CMainFrame(void);~CMainFrame(void);//duilib相关static CMainFrame* Instance();virtual CDuiString     GetSkinFolder();virtual CDuiString     GetSkinFile();virtual LPCTSTR       GetWindowClassName(void) const;CControlUI*            CreateControl(LPCTSTR pstrClass);virtual void SetAnimationPos(const RECT& rect)   //实现位置改变动画接口{CDuiRect r(rect);::MoveWindow(*this,r.left,r.top,r.right-r.left,r.bottom-r.top,false);}virtual void SetAnimationAlpha(const int Alpha){CControlUI* pContrl = m_PaintManager.FindControl(L"alphaChange");String str;str.Format(L"file='alpha.png' fade='%d'",Alpha);pContrl->SetBkImage(str);}virtual void SetAnimationSeqFrame(const int framePos)   //实现序列帧动画接口{CControlUI* pControl = m_PaintManager.FindControl(L"bg");if (framePos==0){pControl->SetBkImage(L"11.jpg");}else if (framePos==1){pControl->SetBkImage(L"12.jpg");}else if (framePos==2){pControl->SetBkImage(L"13.jpg");}else if (framePos==3){pControl->SetBkImage(L"7.jpg");}}//窗口相关void InitWindow();LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);void Notify(TNotifyUI& msg);ScopedPtr<Thread> initThread;ScopedPtr<Thread> destroyThread;ScopedPtr<CloseAnimationListener>  closeListener;ScopedPtr<AlphaChangeListener>   alphaListener;};

首先,将被动画操作的控件事件对应的动画接口,这里以CMainFrame为动画控件,为了方便同时展现三种动画,直接给它把三个动画接口全部实现了,实现具体的动画渲染操作,另外还定义了两个动画监听器的子类CloseAnimationListener,AlphaChangeListener,用来监听动画的运行状态。


下面是实现部分

void CMainFrame::Notify(TNotifyUI& msg){if (_tcsicmp(msg.sType,_T("windowinit"))==0){  closeListener = new CloseAnimationListener;  alphaListener = new AlphaChangeListener;  //创建一个序列帧动画  SeqFrameAnimation* animation = ( SeqFrameAnimation*)AnimationFactory::GetInstance()->CreateAnimation(L"SeqFrame.InitAni",SEQ_FRAME_ANIMATION);  animation->SetIntervalTime(600);   //设置时间间隔  animation->SetFrameSize(4);       //设置帧数  animation->BindObject(this);      //绑定对象  animation->SetLoop(true);         //设置循环  animation->PlayAnimation();       //开始播放  //创建一个渐隐渐显动画  AlphaChangeAnimation* animation2 = ( AlphaChangeAnimation*)AnimationFactory::GetInstance()->CreateAnimation(L"AlphaChange.InitAni",ALPHA_CHANGE_ANIMATION);          animation2->RegistListener(alphaListener);  animation2->SetTotalTime(3000);  animation2->SetKeyFrameRect(0,255);  animation2->BindObject(this);      //绑定对象  animation2->SetLoop(true);         //设置循环  animation2->PlayAnimation();       //开始播放}else if (_tcsicmp(msg.sType,_T("click")) == 0){if (_tcsicmp(msg.pSender->GetName(),_T("btn_close")) == 0){PosChangeAnimation*  animation = (PosChangeAnimation*)AnimationFactory::GetInstance()->CreateAnimation(L"PosChange.CloseAni",POS_CHANGE_ANIMATION);animation->SetTotalTime(600);                       //设置时间RECT rect;GetWindowRect(*this,&rect);RECT rectTo = {rect.left,(rect.top+rect.bottom)/2,rect.right,(rect.top+rect.bottom)/2};animation->SetKeyFrameRect(rect,rectTo);              //设置位移animation->BindObject(this);                          //绑定动画对象animation->SetReverse(false);                         //设置正反向播放,如果不明白改变一下属性试试有什么效果animation->SetLoop(false);                            //设置是否循环播放animation->RegistListener(closeListener);             //绑定监听器animation->PlayAnimation();                           //开始播放}}}

创建动画对象后,设置时间、位移、正反序等属性,绑定驱动对象以及添加监听器,完成这一系列初始化操作后就可以播放了,在播放过程中还可以任意修改动画属性。


下面是skillcore和Demo的下载链接:

skillcore动画Demo下载

 如有问题,或者建议请联系作者:Skilla(QQ:848861075)










1 0
原创粉丝点击