다음을 통해 공유


애니메이션 관리자 업데이트 및 프레임 그리기

애플리케이션이 스토리보드를 예약할 때마다 애플리케이션은 애니메이션 관리자에게 현재 시간을 제공해야 합니다. 애니메이션 관리자가 상태를 업데이트하고 모든 애니메이션 변수를 적절한 보간된 값으로 설정하도록 지시할 때도 현재 시간이 필요합니다.

개요

Windows 애니메이션에서 지원하는 두 가지 구성은 애플리케이션 기반 애니메이션과 타이머 기반 애니메이션입니다.

애플리케이션에서 애플리케이션 기반 애니메이션을 사용하려면 각 프레임을 그리기 전에 애니메이션 관리자를 업데이트하고 적절한 메커니즘을 사용하여 애니메이션에 충분히 자주 프레임을 그려야 합니다. 애플리케이션 기반 애니메이션을 사용하는 애플리케이션은 메커니즘을 사용하여 현재 시간을 확인할 수 있지만 Windows 애니메이션 타이머 개체는 애니메이션 관리자가 허용하는 단위로 정확한 시간을 반환합니다. 애니메이션이 재생되지 않을 때 불필요한 그리기를 방지하려면 애니메이션이 예약될 때 다시 그리기를 시작하고 각 프레임 이후에 다시 그리기를 일시 중단할 수 있는지 여부를 검사 관리자 이벤트 처리기를 제공해야 합니다. 자세한 내용은 애플리케이션 기반 애니메이션을 참조하세요.

애플리케이션 기반 구성에서 애플리케이션은 IUIAnimationManager::GetStatus 메서드를 호출하여 애니메이션이 현재 예약되어 있는지 확인하고 프레임을 계속 그릴 수 있습니다. 예약된 애니메이션이 없으면 다시 그리기가 중지되므로 다음에 애니메이션이 예약될 때 다시 시작해야 합니다. 애플리케이션은 애니메이션 관리자의 상태 유휴(현재 예약된 애니메이션 없음)에서 사용 중으로 변경될 때 알림을 받을 관리자 이벤트 처리기를 등록할 수 있습니다.

애플리케이션에서 타이머 기반 애니메이션을 사용하려면 애니메이션 관리자를 애니메이션 타이머에 연결하고 타이머 이벤트 처리기를 제공해야 합니다. 애니메이션 관리자가 타이머에 연결되면 타이머는 시간이 진행됨에 따라 애니메이션 상태를 업데이트해야 하는 시기를 관리자에게 알릴 수 있습니다. 애플리케이션은 각 타이머 틱에 대한 프레임을 그려야 합니다. 애니메이션 관리자는 재생 중인 애니메이션이 있을 때 타이머에 알릴 수 있으므로 다시 그리기가 필요하지 않은 유휴 기간 동안 타이머가 자체 종료될 수 있습니다. 애니메이션이 재생되지 않을 때 불필요한 그리기를 방지하려면 타이머를 자동으로 사용하지 않도록 구성해야 합니다. 자세한 내용은 타이머 기반 애니메이션을 참조하세요.

코드 예

Application-Driven 애니메이션

다음 예제 코드는 Windows 애니메이션 샘플 애플리케이션 기반 애니메이션그리드 레이아웃에서 ManagerEventHandler.h에서 가져옵니다. 관리자 이벤트 처리기를 정의합니다.

#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;
    }

    ...

};

다음 예제 코드는 Windows 애니메이션 샘플 애플리케이션 기반 애니메이션에서 MainWindow.cpp에서 가져옵니다. CMainWindow::InitializeAnimation을 참조하세요. 이 예제에서는 CreateInstance 메서드를 사용하여 관리자 이벤트 처리기의 instance 만들고 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();
}

관리자 이벤트 처리기는 기본 창 개체에 대한 참조를 유지하므로 관리자 이벤트 처리기를 지워야 합니다(SetManagerEventHandlerNULL을 전달). 그렇지 않으면 기본 창이 제거되기 전에 애니메이션 관리자를 완전히 해제해야 합니다.

다음 예제 코드는 Windows 애니메이션 샘플 애플리케이션 기반 애니메이션의 MainWindow.cpp에서 가져온 것입니다. CMainWindow::OnPaint 메서드를 참조하세요. IUIAnimationManager::GetTime 메서드를 호출하여 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
        );

    ...

}

다음 예제 코드는 Windows 애니메이션 샘플 애플리케이션 기반 애니메이션그리드 레이아웃에서 MainWindow.cpp에서 가져옵니다. CMainWindow::OnPaint 메서드를 참조하세요. 애플리케이션이 모니터 새로 고침 빈도(예: 기본 설정이 있는 Direct2D)에 자동으로 동기화되는 그래픽 API를 사용하고 있다고 가정합니다. 이 경우 InvalidateRect 함수를 호출하면 다음 프레임을 그릴 때 그리기 코드가 다시 호출되도록 할 수 있습니다. InvalidateRect를 무조건 호출하는 대신 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 애니메이션

다음 예제 코드는 Windows 애니메이션 샘플 타이머 기반 애니메이션에서 TimerEventHandler.h에서 가져옵니다. 예제 코드는 타이머 이벤트 처리기를 정의합니다. 이 처리기는 애니메이션 상태를 업데이트할 때마다 창의 클라이언트 영역을 무효화하여 다시 칠합니다.

#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;
    }

    ...

};

다음 예제 코드는 Windows 애니메이션 샘플 타이머 기반 애니메이션에서 MainWindow.cpp에서 가져옵니다. CMainWindow::InitializeAnimation을 참조하세요. 이 예제에서는 CreateInstance 메서드를 사용하여 타이머 이벤트 처리기의 instance 만들고 IUIAnimationTimer::SetTimerEventHandler 메서드를 사용하여 타이머에 전달합니다. 타이머 이벤트 처리기는 기본 창 개체에 대한 참조를 유지하므로 타이머 이벤트 처리기를 지우거나(NULLSetTimerEventHandler에 전달) 기본 창이 제거되기 전에 완전히 해제된 타이머를 지워야 합니다.

// Create and set the timer event handler

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

다음 예제 코드는 Windows 애니메이션 샘플 타이머 기반 애니메이션의 MainWindow.cpp에서 가져온 것입니다. CMainWindow::InitializeAnimation 메서드를 참조하세요. IUIAnimationTimerUpdateHandler에 대한 포인터를 가져오기 위해 애니메이션 관리자 개체에서 QueryInterface 메서드를 호출한 다음, IUIAnimationTimer::SetTimerUpdateHandler 메서드를 사용하여 애니메이션 관리자를 타이머의 업데이트 처리기로 설정하여 UIAnimationManagerUIAnimationTimer 개체를 연결합니다. 이 연결을 명시적으로 지울 필요는 없습니다. 애플리케이션이 애니메이션 관리자와 애니메이션 타이머를 모두 해제한 후 연결이 안전하게 지워집니다.

// 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

        ...

    }
}

UI_ANIMATION_IDLE_BEHAVIOR_DISABLE 사용하지 않는 경우 타이머가 똑딱거리기 시작하도록 설정해야 합니다.

이전 단계

이 단계를 시작하기 전에 애니메이션 변수 만들기 단계를 완료해야 합니다.

다음 단계

이 단계를 완료한 후 다음 단계는 애니메이션 변수 값 읽기입니다.

IUIAnimationManager::GetStatus

IUIAnimationManager::SetManagerEventHandler

IUIAnimationManager::Update

IUIAnimationTimer::GetTime

IUIAnimationTimer::SetTimerUpdateHandler

UIAnimationManager

UIAnimationTimer

Windows 애니메이션 개요