Compartilhar via


Atualizar o Gerenciador de Animação e desenhar quadros

Sempre 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 compatíveis com a Animação do Windows: animação controlada por aplicativo e animação controlada por temporizador.

Para usar a animação controlada 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 um tempo preciso nas unidades aceitas pelo gerenciador de animação. Para evitar desenho desnecessário quando nenhuma animação estiver sendo reproduzida, você também deve fornecer um manipulador de eventos do gerente para começar a redesenhar quando as animações são agendadas e marcar após cada quadro se o redesenho pode ser suspenso. Para obter mais informações, consulte Animação controlada por aplicativo.

Na configuração controlada pelo aplicativo, um aplicativo pode chamar o método IUIAnimationManager::GetStatus para verificar se as animações estão agendadas no momento e continuar a desenhar quadros se estiverem. Como o redesenho para quando não há animações agendadas, é necessário reiniciá-lo na próxima vez que uma animação for agendada. Um aplicativo pode registrar um manipulador de eventos do gerenciador para ser notificado quando o status do gerenciador de animação mudar de ocioso (nenhuma animação está agendada no momento) para ocupado.

Para usar a animação controlada 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 informar ao gerenciador quando o estado da animação deve ser atualizado à medida que o tempo avança. O aplicativo deve desenhar um quadro para cada tique de temporizador. O gerenciador de animação, por sua vez, pode informar o temporizador quando há animações em execução, para que o temporizador possa se desligar durante períodos ociosos quando o redesenho for desnecessário. Para evitar desenho desnecessário quando nenhuma animação estiver sendo reproduzida, você deve configurar o temporizador para desabilitar-se automaticamente. Para obter mais informações, consulte Animação controlada por temporizador.

Código de exemplo

Animação Application-Driven

O código de exemplo a seguir é obtido de ManagerEventHandler.h dos exemplos de Animação do Windows Animação Controlada por Aplicativo e Layout de Grade. Ele define o manipulador de eventos do gerenciador.

#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 é obtido de MainWindow.cpp da animação de exemplo de animação do Windows Animação controlada por aplicativos; consulte CMainWindow::InitializeAnimation. Este exemplo cria uma instância do manipulador de eventos do gerenciador usando o método CreateInstance e o passa para o gerenciador de animação usando o método IUIAnimationManager::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 gerenciador retém uma referência ao objeto de janela main, o manipulador de eventos do gerenciador deve ser limpo (passando NULL para SetManagerEventHandler) ou o gerenciador de animação deve ser completamente liberado antes que a janela main seja destruída.

O código de exemplo a seguir é obtido de MainWindow.cpp na animação de exemplo de animação do Windows Animação controlada por aplicativos; consulte o método CMainWindow::OnPaint. Ele chama o método IUIAnimationManager::GetTime para recuperar o tempo nas unidades exigidas pelo método IUIAnimationManager::Update .

// 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 é obtido de MainWindow.cpp dos exemplos de Animação do Windows Animação Controlada por Aplicativo e Layout de Grade; consulte o método CMainWindow::OnPaint. Ele pressupõe que o aplicativo esteja usando uma API de gráficos que é sincronizada automaticamente com a taxa de atualização do monitor (como Direct2D com suas configurações padrão), nesse caso, uma chamada para a função InvalidateRect é suficiente para garantir que o código de pintura seja chamado novamente quando for a hora de desenhar o próximo quadro. Em vez de chamar InvalidateRect incondicionalmente, é melhor marcar se ainda houver animações agendadas 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
                );
        }
    }
}

Animação Timer-Driven

O código de exemplo a seguir é obtido de TimerEventHandler.h da animação orientada por temporizador de exemplo de animação do Windows. O código de exemplo define o manipulador de eventos do temporizador, que invalida a área de cliente da janela para causar uma repinta após cada atualização do estado de 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 é obtido de MainWindow.cpp da animação de exemplo de animação do Windows Animação controlada por temporizador; consulte CMainWindow::InitializeAnimation. Este exemplo cria uma instância do manipulador de eventos de temporizador usando o método CreateInstance e o passa para o temporizador usando o método IUIAnimationTimer::SetTimerEventHandler . Como o manipulador de eventos de temporizador retém uma referência ao objeto de janela main, o manipulador de eventos do temporizador deve ser limpo (passando NULL para SetTimerEventHandler) ou o temporizador completamente liberado antes que a janela main seja 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 é obtido de MainWindow.cpp na animação orientada por temporizador de exemplo de animação do Windows; consulte o método CMainWindow::InitializeAnimation. Ele chama o método QueryInterface no objeto do gerenciador de animação para obter um ponteiro para os objetos IUIAnimationTimerUpdateHandler e 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 . Observe que não é necessário limpar explicitamente essa conexã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 usado, também será necessário habilitar o temporizador para iniciá-lo.

Etapa anterior

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

Próxima etapa

Depois de concluir esta etapa, a próxima etapa é: Ler os valores da variável de animação.

IUIAnimationManager::GetStatus

IUIAnimationManager::SetManagerEventHandler

IUIAnimationManager::Update

IUIAnimationTimer::GetTime

IUIAnimationTimer::SetTimerUpdateHandler

UIAnimationManager

UIAnimationTimer

Visão geral da animação do Windows