Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Animating View Transitions on Windows Mobile

0.00/5 (No votes)
6 Jun 2008 2  
How to animate child view transitions on a Windows Mobile WTL application.

SlideView/slideview.gif

Introduction

This article shows how to animate child view transitions on a WTL 8.0 Windows Mobile application.

Background

The idea for researching the code for this article came after reading Tim Brook's article on how to switch views in a WTL SDI application. This technique is quite useful for Windows Mobile applications because the platform does not support MDI (although you can use tabbed views).

After testing Tim's idea, I thought about animating the child view transitions. This would be a bit better than just replacing the old view with the new one. Why not add a bit of FX and make it a bit more interesting to the eye? Also, the developer may want to use the child transition animations to convey the idea of spatial navigation to the user: the new view might be shown scrolling up when the user drills-down to more detailed information, and scrolling up when returning to the previous level.

Using the code

For the developer's convenience, I put all the required code into mix-in classes that must be listed in the public inheritance list of both the main frame and all the animated child view windows that will be hosted by the frame.

Main frame code

Coding the main frame is quite easy. Start by adding the CChildViewAnimate template class to your main frame inheritance list:

class CMainFrame :
    public CFrameWindowImpl<CMainFrame>, 
    public CUpdateUI<CMainFrame>,
    public CChildViewAnimate<CMainFrame>,
    public CMessageFilter, 
    public CIdleHandler

Next, you need to make a small change to your PreTranslateMessage handler:

virtual BOOL PreTranslateMessage(MSG* pMsg)
{
    if(CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg))
        return TRUE;

    return ChildPreTranslateMessage(pMsg);
}

The call to ChildPreTranslateMessage transfers execution to the current child view message translation (useful for child dialogs).

Finally, you must initialize the current view pointer on the frame's OnCreate handler:

...
m_hWndClient = m_viewForm.Create(m_hWnd);
m_pView = &m_viewForm;
...

The m_pView member points to the current view and is used by the CChildViewAnimate code.

Child view code

On the child view class, you only need to add the CChildView class template to the inheritance list and optionally override the PreTranslateMessage virtual method. Here's the sample's form view class:

class CSlideFormView :
    public CDialogImpl<CSlideFormView>,
    public CChildView<CSlideFormView>
{
public:
    enum { IDD = IDD_SLIDEVIEW_FORM };

    virtual BOOL PreTranslateMessage(MSG* pMsg)
    {
        if(!::IsWindow(m_hWnd))
            return FALSE;
        return CWindow::IsDialogMessage(pMsg);
    }

    BEGIN_MSG_MAP(CSlideFormView)
    END_MSG_MAP()
};

Animating child views

Child view transitions are animated by scrolling left, right, up, or down. The old view and the new one are scrolled together to give the user an idea of continuous movement.

Before we can scroll a new view into position, we must first create it. When the new view is created, it is very important not to show it immediately, so I opted to give every new view a rectangle of the same size as the current view, but offset to the right so it does not show on top of the current view. You can see how this is done in the sample application when both the tree and the list views are created:

CWindow wndView(*m_pView);

wndView.GetClientRect(&rc);

nWidth   = rc.Width();
rc.left  += nWidth;
rc.right += nWidth;

hWnd = m_viewList.Create(m_hWnd, &rc, NULL, dwStyle);

After successfully creating the new child view, you can then animate it into view by calling:

SwitchToView(&m_viewList, m_nAnimate);

The m_nAnimate member variable stores one of the predefined animation modes:

enum ViewAnimation
{
    None,        // Don't animate the child transitions
    ScrollLeft,  // Scroll the views to the left
    ScrollRight, // Scroll the views to the right
    ScrollUp,    // Scroll the views up
    ScrollDown   // Scroll the views down
};

When SwitchToView returns, the active child view has been correctly set according to Tim's method of changing the child window ID.

Implementation

Child view animation is implemented in the protected AnimateView method of the CChildViewAnimate class. The code starts by rendering into a bitmap the contents of the child view area, and then uses it to paint the main frame client area. The scrolling process just synchronizes the main frame client area scrolling with moving the new child view into position. I designed the process this way to avoid having to repaint both views while scrolling them (might be slower).

Also, while the new child window is moved into position, the code makes sure only to invalidate the new portion of the window that is displayed at any given scrolling step. This also helps making the whole process smoother.

Finally, there is a method worth mentioning: ScrollWait. When scrolling the main frame client area, I found out that the less bits you scroll, the faster the scrolling gets (easy to guess why). This meant that my early experiences with this code were accelerated: the scrolling speed increased. This is an unpleasant experience for the user, so I figured out a very simple way to scroll at an apparent constant speed. The first scroll is timed using GetTickCount, and all subsequent scrolls are "time-padded" with a very simple CPU burning loop:

void ScrollWait(DWORD dwTickIni, DWORD dwTickEnd)
{
    DWORD dwTickDel = dwTickEnd - dwTickIni;

    if(dwTickDel > m_dwMaxTick)
    {
        m_dwMaxTick = dwTickDel;
    }
    else
    {
        // Preserve original timing (yes, this burns the CPU)
        while(GetTickCount() - dwTickIni < m_dwMaxTick)
            ;
    }
}

The m_dwMaxTick stores the maximum number of ticks a scroll takes in a given animation. Not terribly clever, but effective.

Points of interest

As you can see from the sample, there are three different views that you can animate: a form, a list, and a tree. If you look at the tree implementation, you will see that it is very different from the list's: the tree is hosted in another window. While the list view window is the child view, the tree view had to be hosted in another window for a very strange reason: it would not paint correctly when scrolled into view. Why? I actually don't know...

Finally, you might be interested in looking at the included CSelectionBar class. This is a rough first WTL implementation of a Pocket PC header bar (I had already written an implementation in MFC, but it looks so much better in WTL!). It does not have a full set of features yet, but I promise to publish it here when it does.

History

  • 2008-06-12 - Added illustrating animation.
  • 2008-06-06 - First publication.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here