Symbian 实现基于传统架构场景切换动画

来源:互联网 发布:科怡软件设置 编辑:程序博客网 时间:2024/06/08 18:33

简介 

  在symbian界面开发中,我还是比较喜欢实用基于传统结构(Constructing views in traditional architecture)设计界面,虽然这样做比较繁琐,界面基本上是自己画出来的,但是, 这样做的灵活性很高,基本可以实现任何自己想要的界面。一般每一个界面都是一个CCoeControl的对象,通过MakeVisible(TBool)来设置其可见或者隐藏。这样切换当然是很生硬的,如果能在切换的时候加一个转换效果,自然好多了,现在很多软件都有场景切换动画的。可以是滑入滑出,淡入淡出等等! 

  在基于传统ui架构的模式下,如何切换显示界面 

  一般切换界面的方法为设置当前界面MakeVisible(EFalse),下一界面MakeVisible(ETRue),还要管理堆栈,以便于响应键盘按键: 

  CCoeControl * iControl1; 

  CCoeControl * iControl2; 

  // Construct 

  .. 

  iControl2->MakeVisible(ETrue);// show 

  iControl1->MakeVisible(EFalse);// hide 

  CAppUI * appui = CEikonEnv::Static()->EikAppUi(); 

  // 注意,这里的CAppUI是你程序的UI类 

  appui->AddToStackL(iControl2);// 添加到栈中 

  appui->RemoveFromStack(iControl1);// 移除出栈 

  .. 

  CCoeControl * iControl1; 

  CCoeControl * iControl2; 

  // Construct 

  .. 

  iControl2->MakeVisible(ETrue);// show 

  iControl1->MakeVisible(EFalse);// hide 

  CAppUI * appui = CEikonEnv::Static()->EikAppUi(); 

  // 注意,这里的CAppUI是你程序的UI类 

  appui->AddToStackL(iControl2);// 添加到栈中 

  appui->RemoveFromStack(iControl1);// 移除出栈 

  .. 

  实现场景切换动画的原理 

  实现场景切换动画,当然需要前后界面的截图,在这两张图上面做文章就可以了,然而,要如何获得这两张图确是个问题,前面这个界面的截图还可以通话获屏幕截图的方法来实现,然而,第二个界面呢?还没有画到界面上的,使用前面的方法是做不到的,我们不能先画到屏幕上,再来截图的。 

  ps。。既然说到获得屏幕截图,就写一下获得屏幕截图的方法吧: 

  // Get the screen device 

  CWsScreenDevice * iScreenDevice = CCoeEnv::Static()->ScreenDevice(); 

  // new instance 

  iScreenBitmap = new (ELeave) CFbsBitmap; 

  // push 

  CleanupStack: ushL(iScreenBitmap); 

  // create 

  User: eaveIfError(iScreenBitmap->Create(iScreenDevice->Siz eInPixels(),iScreenDevice->DisplayMode())); 

  // copy screen to bitmap 

  User: eaveIfError(iScreenDevice->CopyScreenToBitmap(iScre enBitmap)); 

  // pop 

  CleanupStack: op(iScreenBitmap); 

  // Get the screen device 

  CWsScreenDevice * iScreenDevice = CCoeEnv::Static()->ScreenDevice(); 

  // new instance 

  iScreenBitmap = new (ELeave) CFbsBitmap; 

  // push 

  CleanupStack: ushL(iScreenBitmap); 

  // create 

  User: eaveIfError(iScreenBitmap->Create(iScreenDevice->Siz eInPixels(),iScreenDevice->DisplayMode())); 

  // copy screen to bitmap 

  User: eaveIfError(iScreenDevice->CopyScreenToBitmap(iScre enBitmap)); 

  // pop 

  CleanupStack: op(iScreenBitmap); 

  回到原来的话题,我们可以想办法把控件绘制到位图上面,这样就可以获得截图了。 

  我当初想的方法就是使用双缓冲,先把控件绘制到位图上,也就是说我自己写一个可以调用的Draw方法,然而,系统控件确没有办法这样实现,例如编辑框等,因为,这些控件是系统去调用它们的Draw函数的。。所以这种方法不可行。 

  其实,CCoeControl类有提供一个SetGC()函数,可以设置绘图上下文,系统默认设置的是CEikonEnv::Static()->SystemGc();这个gc当然是画到了屏幕上面,我们可以通过调用函数SetGC()设置一个指向一张位图的绘图上下文,这样,就可以获得前后界面的截图了 

  获得前后界面的截图 

  /** 

  * 将一个界面绘制到位图上 

  */ 

  void DrowScreenInBitmap(CCoeControl* iScreen,CFbsBitmap * iBitmap){ 

  CleanupStack: ushL(iBitmap); 

  // 获得屏幕设备 

  CWsScreenDevice * iScreenDevice = CEikonEnv::Static()->ScreenDevice(); 

  //建立位图设备 

  CFbsBitmapDevice * iDevice = CFbsBitmapDevice::NewL(iBitmap); 

  CleanupStack: ushL(iDevice); 

  // 创建位图设备的绘图上下文 

  CFbsBitGc * gc = NULL; 

  User: eaveIfError(iDevice->CreateContext(gc)); 

  CleanupStack: ushL(gc); 

  // SetGc()函数所使用的绘图上下文必须是指向窗口的,因此,必须对gc做一下映射(mapping) 

  CWindowToBitmapMappingGc *wbgc = CWindowToBitmapMappingGc::NewL(*iScreenDevice,*gc) ; 

  CleanupStack: ushL(wbgc); 

  // 这个是自己定义的函数,对每个控件以及它的所有子控件设置GC 

  SetGc(iScreen,wbgc); 

  // 调用重绘,此时,控件绘制到了位图上 

  iScreen->DrawNow(); 

  // 绘制完之后,设置回原来的GC 

  SetGc(iScreen,NULL); 

  CleanupStack: opAndDestroy(wbgc); 

  CleanupStack: opAndDestroy(gc); 

  CleanupStack::PopAndDestroy(iDevice); 

  CleanupStack::Pop(iBitmap); 

  } 

  /** 

  * 为每一控件以及它的所有子控件重新设置gc 

  */ 

  void SetGc(CCoeControl * iControl,CWindowToBitmapMappingGc* wsgc){ 

  iControl ->SetGc(wsgc); 

  TInt count = iControl->CountComponentControls(); 

  if(count == 0){ 

  return; 

  } 

  for(TInt index = 0; index < count; ++index){ 

  SetGc(iControl->ComponentControl(index),wsgc); 

  } 

  } 

  /** 

  * 将一个界面绘制到位图上 

  */ 

  void DrowScreenInBitmap(CCoeControl* iScreen,CFbsBitmap * iBitmap){ 

  CleanupStack::PushL(iBitmap); 

  // 获得屏幕设备 

  CWsScreenDevice * iScreenDevice = CEikonEnv::Static()->ScreenDevice(); 

  //建立位图设备 

  CFbsBitmapDevice * iDevice = CFbsBitmapDevice::NewL(iBitmap); 

  CleanupStack::PushL(iDevice); 

  // 创建位图设备的绘图上下文 

  CFbsBitGc * gc = NULL; 

  User: eaveIfError(iDevice->CreateContext(gc)); 

  CleanupStack::PushL(gc); 

  // SetGc()函数所使用的绘图上下文必须是指向窗口的,因此,必须对gc做一下映射(mapping) 

  CWindowToBitmapMappingGc *wbgc = CWindowToBitmapMappingGc::NewL(*iScreenDevice,*gc) ; 

  CleanupStack::PushL(wbgc); 

  // 这个是自己定义的函数,对每个控件以及它的所有子控件设置GC 

  SetGc(iScreen,wbgc); 

  // 调用重绘,此时,控件绘制到了位图上 

  iScreen->DrawNow(); 

  // 绘制完之后,设置回原来的GC 

  SetGc(iScreen,NULL); 

  CleanupStack::PopAndDestroy(wbgc); 

  CleanupStack::PopAndDestroy(gc); 

  CleanupStack::PopAndDestroy(iDevice); 

  CleanupStack::Pop(iBitmap); 

  } 

  /** 

  * 为每一控件以及它的所有子控件重新设置gc 

  */ 

  void SetGc(CCoeControl * iControl,CWindowToBitmapMappingGc* wsgc){ 

  iControl ->SetGc(wsgc); 

  TInt count = iControl->CountComponentControls(); 

  if(count == 0){ 

  return; 

  } 

  for(TInt index = 0; index < count; ++index){ 

  SetGc(iControl->ComponentControl(index),wsgc); 

  } 

  } 

  动画的实现 

  我们已经可以获得前后界面的截图了,有了这两张截图,我相信动画的实现就比较简单了,对这两张图进行合并,透明什么的,绘制到另一个界面上,这个界面可以用来专门显示场景切换的动画,只要使用一个活动对象或者定时器,动态改变绘制的内容,就可以实现了 

原创粉丝点击