Partilhar via


Atualizar o Gerenciador de Animações e desenhar quadros

Cada vez que um aplicativo agenda um storyboard, o aplicativo deve fornecer a hora atual para o gerenciador de animação. A hora atual também é necessária ao direcionar o gerenciador de animação para atualizar seu estado e definir todas as variáveis de animação para os valores interpolados apropriados.

Visão geral

Há duas configurações suportadas pela Animação do Windows: animação orientada por aplicativo e animação orientada por temporizador.

Para usar a animação orientada por aplicativo em seu aplicativo, você deve atualizar o gerenciador de animação antes de desenhar cada quadro e usar um mecanismo apropriado para desenhar quadros com frequência suficiente para animação. Um aplicativo que usa animação controlada por aplicativo pode usar qualquer mecanismo para determinar a hora atual, mas o objeto de temporizador de animação do Windows retorna uma hora precisa nas unidades aceitas pelo gerenciador de animação. Para evitar desenhos desnecessários quando nenhuma animação estiver sendo reproduzida, você também deve fornecer um manipulador de eventos do gerenciador para iniciar o redesenho quando as animações forem agendadas e verificar após cada quadro se o redesenho pode ser suspenso. Para obter mais informações, consulte Application-Driven Animation.

Na configuração orientada para aplicações, uma aplicação pode chamar o método IUIAnimationManager::GetStatus para verificar se as animações estão atualmente agendadas e continuar a renderizar frames, se estiverem. Como o redesenho para quando não há animações agendadas, é necessário reiniciá-lo da próxima vez que uma animação for programada. Uma aplicação pode registar um controlador de eventos do gestor para ser notificado quando o estado do gestor de animação passar de inativo (nenhuma animação está agendada no momento) para ativo.

Para usar a animação orientada por temporizador em seu aplicativo, você deve conectar o gerenciador de animação a um temporizador de animação e fornecer um manipulador de eventos de temporizador. Quando o gerenciador de animação está conectado a um temporizador, o temporizador pode dizer ao gerente quando o estado da animação deve ser atualizado à medida que o tempo avança. A aplicação deve desenhar uma moldura para cada tique do temporizador. O gestor de animações pode, por sua vez, informar o temporizador quando há animações a reproduzir, para que o temporizador possa desligar-se durante períodos de inatividade quando o redesenho é desnecessário. Para evitar a renderização desnecessária quando não há animações em reprodução, deve-se configurar o temporizador para se desativar automaticamente. Para obter mais informações, consulte Timer-Driven Animation.

Código de exemplo

Application-Driven Animação

O código de exemplo a seguir é retirado de ManagerEventHandler.h dos exemplos de animação do Windows Application-Driven Animation e Grid Layout. Ele define o manipulador de eventos do gerente.

#include "UIAnimationHelper.h"

// Event handler object for manager status changes

class CManagerEventHandler :
    public CUIAnimationManagerEventHandlerBase<CManagerEventHandler>
{
public:

    static HRESULT
    CreateInstance
    (
        CMainWindow *pMainWindow,
        IUIAnimationManagerEventHandler **ppManagerEventHandler
    ) throw()
    {
        CManagerEventHandler *pManagerEventHandler;
        HRESULT hr = CUIAnimationCallbackBase::CreateInstance(
            ppManagerEventHandler,
            &pManagerEventHandler
            );
        if (SUCCEEDED(hr))
        {
            pManagerEventHandler->m_pMainWindow = pMainWindow;
        }
        
        return hr;
    }

    // IUIAnimationManagerEventHandler

    IFACEMETHODIMP
    OnManagerStatusChanged
    (
        UI_ANIMATION_MANAGER_STATUS newStatus,
        UI_ANIMATION_MANAGER_STATUS previousStatus
    )
    {
        HRESULT hr = S_OK;

        if (newStatus == UI_ANIMATION_MANAGER_BUSY)
        {
            hr = m_pMainWindow->Invalidate();
        }

        return hr;
    }

    ...

};

O código de exemplo a seguir é retirado de MainWindow.cpp do exemplo de Animação do Windows Application-Driven Animation; consulte CMainWindow::InitializeAnimation. Este exemplo cria uma instância do manipulador de eventos do gerenciador usando o método CreateInstance e a passa para o gerenciador de animações usando o métodoIUIAnimationManager::SetManagerEventHandler.

// Create and set the ManagerEventHandler to start updating when animations are scheduled

IUIAnimationManagerEventHandler *pManagerEventHandler;
HRESULT hr = CManagerEventHandler::CreateInstance(
    this,
    &pManagerEventHandler
    );
if (SUCCEEDED(hr))
{
    hr = m_pAnimationManager->SetManagerEventHandler(
        pManagerEventHandler
        );
    pManagerEventHandler->Release();
}

Como o manipulador de eventos do gestor mantém uma referência ao objeto da janela principal, o manipulador de eventos do gestor deve ser limpo (passando NULL para SetManagerEventHandler) ou o gestor de animação deve ser completamente liberado antes que a janela principal seja destruída.

O código de exemplo a seguir é retirado de MainWindow.cpp no exemplo de Animação do Windows Application-Driven Animation; consulte o método CMainWindow::OnPaint. Ele chama o IUIAnimationManager::GetTime método para recuperar o tempo nas unidades exigidas pelo IUIAnimationManager::Update método.

// Update the animation manager with the current time

UI_ANIMATION_SECONDS secondsNow;
HRESULT hr = m_pAnimationTimer->GetTime(
    &secondsNow
    );

if (SUCCEEDED(hr))
{
    hr = m_pAnimationManager->Update(
        secondsNow
        );

    ...

}

O código de exemplo a seguir é retirado de MainWindow.cpp dos exemplos de Animação do Windows Application-Driven Animation e Grid Layout; consulte o método CMainWindow::OnPaint. Assume-se que o aplicativo está a usar uma interface de programação gráfica que sincroniza automaticamente com a taxa de atualização do monitor (como o Direct2D com as suas definições padrão), caso em que uma chamada para a função InvalidateRect é suficiente para garantir que o código de pintura será chamado novamente quando chegar a altura de desenhar o próximo frame. Em vez de chamar InvalidateRect de forma incondicional, é melhor verificar se ainda há animações programadas usando GetStatus.

// Read the values of the animation variables and draw the client area

hr = DrawClientArea();
if (SUCCEEDED(hr))
{          
    // Continue redrawing the client area as long as there are animations scheduled
    UI_ANIMATION_MANAGER_STATUS status;
    hr = m_pAnimationManager->GetStatus(
        &status
        );
    if (SUCCEEDED(hr))
    {
        if (status == UI_ANIMATION_MANAGER_BUSY)
        {
            InvalidateRect(
                m_hwnd,
                NULL,
                FALSE
                );
        }
    }
}

Timer-Driven Animação

O código de exemplo a seguir é retirado de TimerEventHandler.h do exemplo de animação do Windows Timer-Driven Animation. O código de exemplo define o manipulador de eventos do temporizador, que invalida a área cliente da janela para forçar uma repintura após cada atualização do estado da animação.

#include "UIAnimationHelper.h"

// Event handler object for timer events

class CTimerEventHandler :
    public CUIAnimationTimerEventHandlerBase<CTimerEventHandler>
{
public:

    static HRESULT
    CreateInstance
    (
        CMainWindow *pMainWindow,
        IUIAnimationTimerEventHandler **ppTimerEventHandler
    ) throw()
    {
        CTimerEventHandler *pTimerEventHandler;
        HRESULT hr = CUIAnimationCallbackBase::CreateInstance(
            ppTimerEventHandler,
            &pTimerEventHandler
            );

        if (SUCCEEDED(hr))
        {
            pTimerEventHandler->m_pMainWindow = pMainWindow;
        }
        
        return hr;
    }

    // IUIAnimationTimerEventHandler

    IFACEMETHODIMP
    OnPreUpdate()
    {
        return S_OK;
    }

    IFACEMETHODIMP
    OnPostUpdate()
    {
        HRESULT hr = m_pMainWindow->Invalidate();

        return hr;
    }

    IFACEMETHODIMP
    OnRenderingTooSlow
    (
        UINT32 /* fps */
    )
    {
        return S_OK;
    }

    ...

};

O código de exemplo a seguir é retirado de MainWindow.cpp do exemplo de Animação do Windows Timer-Driven Animation; consulte CMainWindow::InitializeAnimation. Este exemplo cria uma instância do manipulador de eventos de timer usando o método CreateInstance e a passa para o temporizador usando o IUIAnimationTimer::SetTimerEventHandler método. Como o controlador de eventos do temporizador mantém uma referência ao objeto da janela principal, o controlador de eventos do temporizador deve ser removido (passando NULL para SetTimerEventHandler) ou o temporizador completamente desativado antes de a janela principal ser destruída.

// Create and set the timer event handler

IUIAnimationTimerEventHandler *pTimerEventHandler;
hr = CTimerEventHandler::CreateInstance(
    this,
    &pTimerEventHandler
    );
if (SUCCEEDED(hr))
{
    hr = m_pAnimationTimer->SetTimerEventHandler(
        pTimerEventHandler
        );
    pTimerEventHandler->Release();
}

O código de exemplo a seguir é retirado de MainWindow.cpp no exemplo de Animação do Windows Timer-Driven Animation; consulte o método CMainWindow::InitializeAnimation. Ele chama o método QueryInterface no objeto do gerenciador de animação para obter um ponteiro para IUIAnimationTimerUpdateHandler, depois conecta os objetos UIAnimationManager e UIAnimationTimer , definindo o gerenciador de animação como o manipulador de atualização do temporizador, usando o método IUIAnimationTimer::SetTimerUpdateHandler . Note-se que não é necessário limpar explicitamente esta ligação; A conexão é limpa com segurança depois que o aplicativo libera o Gerenciador de Animação e o temporizador de animação.

// Connect the animation manager to the timer

IUIAnimationTimerUpdateHandler *pTimerUpdateHandler;
hr = m_pAnimationManager->QueryInterface(
    IID_PPV_ARGS(&pTimerUpdateHandler)
    );

if (SUCCEEDED(hr))
{
    hr = m_pAnimationTimer->SetTimerUpdateHandler(
        pTimerUpdateHandler
        UI_ANIMATION_IDLE_BEHAVIOR_DISABLE  // timer will shut itself off when there are no animations playing
        );
    pTimerUpdateHandler->Release();
    if (SUCCEEDED(hr))
    {
        // Create and set the timer event handler

        ...

    }
}

Se UI_ANIMATION_IDLE_BEHAVIOR_DISABLE não for utilizado, também é necessário ativar o temporizador para que este comece a contar.

Etapa anterior

Antes de iniciar esta etapa, você deve ter concluído esta etapa: Criar variáveis de animação.

Próximo Passo

Depois de concluir esta etapa, a próxima etapa é: Ler os Valores da Variável de Animação.

IUIAnimationManager::GetStatus

IUIAnimationManager::SetManagerEventHandler

IUIAnimationManager::Atualização

IUIAnimationTimer::GetTime

IUIAnimationTimer::SetTimerUpdateHandler

UIAnimationManager

UIAnimationTimer

Visão geral da animação do Windows