애니메이션에 대한 유용한 정보

WPF에서 애니메이션을 사용할 때 애니메이션 성능을 높이고 문제를 줄일 수 있는 다양하고 유용한 정보가 있습니다.

일반적인 문제

스크롤 막대 또는 슬라이더의 위치에 애니메이션 효과를 줄 경우 고정됨

FillBehaviorHoldEnd(기본값)인 애니메이션을 사용하여 스크롤 막대 또는 슬라이더의 위치에 애니메이션 효과를 줄 경우 사용자는 더 이상 스크롤 막대 또는 슬라이더를 이동할 수 없습니다. 그 이유는 애니메이션이 종료되더라도 대상 속성의 기본값은 여전히 재정의되기 때문입니다. 애니메이션이 속성의 현재 값을 재정의하는 것을 방지하려면 애니메이션을 제거하거나 StopFillBehavior를 제공합니다. 자세한 내용 및 예제를 보려면 스토리보드를 사용하여 애니메이션 효과를 적용한 후 속성 설정을 참조하세요.

애니메이션의 출력에 애니메이션을 적용해도 효과가 없음

다른 애니메이션의 출력에 해당하는 개체에 애니메이션 효과를 줄 수 없습니다. 예를 들어, 사용 하는 경우는 ObjectAnimationUsingKeyFrames 애니메이션 효과를 FillRectangle 에서 RadialGradientBrushSolidColorBrush의 모든 속성에 애니메이션을 적용할 수 없습니다는 RadialGradientBrush 또는 SolidColorBrush.

애니메이션 효과를 적용한 후 속성 값을 변경할 수 없음

경우에 따라 애니메이션이 종료된 후에도 애니메이션 효과를 적용한 속성의 값을 변경할 수 없는 것처럼 나타납니다. 그 이유는 애니메이션이 종료되더라도 속성의 기본값은 여전히 재정의되기 때문입니다. 애니메이션이 속성의 현재 값을 재정의하는 것을 방지하려면 애니메이션을 제거하거나 StopFillBehavior를 제공합니다. 자세한 내용 및 예제를 보려면 스토리보드를 사용하여 애니메이션 효과를 적용한 후 속성 설정을 참조하세요.

타임라인을 변경해도 효과가 없음

대부분의 Timeline 속성은 애니메이션 효과를 줄 수 있고 데이터 바인딩이 가능하지만 활성 Timeline의 속성 값 변경은 효과가 없는 것처럼 보입니다. 그 이유는 Timeline이 시작될 때 타이밍 시스템이 Timeline의 복사본을 만들어 Clock 개체를 만드는 데 사용하기 떄문입니다. 원본을 수정해도 시스템의 복사본에는 영향을 주지 않습니다.

Timeline이 변경 내용을 반영하려면 해당 시계를 다시 생성한 후 이전에 만든 시계를 대체해야 합니다. 클록은 자동으로 다시 생성되지 않습니다. 다음은 타임라인 변경 내용을 적용하는 몇 가지 방법입니다.

  • 타임 라인은 또는에 속하는 경우는 Storyboard를 사용 하 여 해당 storyboard를 다시 적용 하 여 변경 내용을 반영 만들 수 있습니다를 BeginStoryboard 또는 Begin 메서드. 부작용으로 애니메이션까지 다시 시작됩니다. 코드에서 사용할 수는 Seek 메서드 storyboard를 이전 위치로 다시 합니다.

  • 사용 하 여 속성에 직접 애니메이션을 적용 하는 경우는 BeginAnimation 메서드를 호출 합니다 BeginAnimation 메서드를 다시 수정 된 애니메이션을 전달 합니다.

  • 클록 수준에서 직접 작업하는 경우 새 클록 집합을 만들어 적용하고 이 클록 집합을 사용하여 이전에 생성된 클록 집합을 대체합니다.

타임라인 및 시계에 대한 자세한 내용은 애니메이션 및 타이밍 시스템 개요를 참조하세요.

FillBehavior.Stop이 예상대로 작동하지 않음

HandoffBehavior 설정이 SnapshotAndReplace이기 때문에 한 애니메이션이 다른 애니메이션으로 “전달”하는 경우처럼 FillBehavior 속성을 Stop으로 설정해도 아무 효과가 없는 것처럼 보일 때가 있습니다.

다음 예제는 Canvas, Rectangle, TranslateTransform을 만듭니다. TranslateTransform에는 Canvas에서 Rectangle을 움직이는 애니메이션 효과가 적용됩니다.

<Canvas Width="600" Height="200">
  <Rectangle 
    Canvas.Top="50" Canvas.Left="0" 
    Width="50" Height="50" Fill="Red">
    <Rectangle.RenderTransform>
      <TranslateTransform 
        x:Name="MyTranslateTransform" 
        X="0" Y="0" />
    </Rectangle.RenderTransform>
  </Rectangle>
</Canvas>

이 섹션의 예제는 이전 개체를 사용하여 FillBehavior 속성이 예상대로 동작하지 않는 몇 가지 경우를 보여 줍니다.

여러 애니메이션에서의 FillBehavior="Stop" 및 HandoffBehavior

경우에 따라 애니메이션이 두 번째 애니메이션으로 대체될 때 해당 FillBehavior 속성을 무시하는 것처럼 보입니다. 다음 예제에서는 2개의 Storyboard 개체를 만들어 이전 예제에 나온 TranslateTransform을 만듭니다.

첫 번째 StoryboardB1TranslateTransformX 속성에 0에서 350으로 애니메이션 효과를 주어 사각형이 오른쪽으로 350픽셀 이동합니다. 애니메이션 재생 시간이 끝나서 재생을 중지하면 X 속성은 원래 값인 0으로 돌아갑니다. 결과적으로 사각형은 오른쪽으로 350픽셀만큼 이동한 다음 원래 위치로 되돌아갑니다.

<Button Content="Start Storyboard B1">
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Click">
      <BeginStoryboard>
        <Storyboard x:Name="B1">
          <DoubleAnimation 
            Storyboard.TargetName="MyTranslateTransform"
            Storyboard.TargetProperty="X"
            From="0" To="350" Duration="0:0:5"
            FillBehavior="Stop"
            />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Button.Triggers>
</Button>

두 번째 StoryboardB2도 동일한 XTranslateTransform 속성에 애니메이션 효과를 줍니다. 이 Storyboard에서 애니메이션의 To 속성만 설정되었기 때문에 애니메이션은 애니메이션 효과를 주는 속성의 현재 값을 시작 값으로 사용합니다.


<!-- Animates the same object and property as the preceding
     Storyboard. -->
<Button Content="Start Storyboard B2">
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Click">
      <BeginStoryboard>
        <Storyboard x:Name="B2">
          <DoubleAnimation 
            Storyboard.TargetName="MyTranslateTransform"
            Storyboard.TargetProperty="X"
            To="500" Duration="0:0:5" 
            FillBehavior="Stop" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Button.Triggers>
</Button>

첫 번째 Storyboard가 재생되는 동안 두 번째 단추를 클릭하면 다음과 같은 동작을 예상할 수 있습니다.

  1. 애니메이션의 FillBehaviorStop이므로 첫 번째 스토리보드가 끝나고 사각형을 원래 위치로 보냅니다.

  2. 두 번째 Storyboard가 적용되며, 0에 해당하는 현재 위치에서 500으로 애니메이션 효과를 줍니다.

그러나 이 작업이 수행되지 않습니다. 대신, 사각형이 원래 위치로 돌아가지 않고 계속 오른쪽으로 이동됩니다. 그 이유는 두 번째 애니메이션이 첫 번째 애니메이션의 현재 값을 시작 값으로 사용하고 해당 값에서 500으로 애니메이션 효과를 주기 때문입니다. 두 번째 애니메이션이 첫 번째를 대체할 때 SnapshotAndReplaceHandoffBehavior가 사용되기 때문에 첫 번째 애니메이션의 FillBehavior는 문제가 되지 않습니다.

FillBehavior 및 Completed 이벤트

다음 예제는 StopFillBehavior가 효과가 없는 것처럼 보이는 또 다른 시나리오를 보여 줍니다. 여기에서도 예제는 스토리보드를 사용하여 TranslateTransformX 속성에 0에서 350으로 애니메이션 효과를 줍니다. 하지만 이번에는 예제가 Completed 이벤트에 등록합니다.

<Button Content="Start Storyboard C">
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Click">
      <BeginStoryboard>
        <Storyboard Completed="StoryboardC_Completed">
          <DoubleAnimation 
            Storyboard.TargetName="MyTranslateTransform"
            Storyboard.TargetProperty="X"
            From="0" To="350" Duration="0:0:5"
            FillBehavior="Stop" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Button.Triggers>
</Button>

Completed 이벤트 처리기는 동일한 속성에 현재 값에서 500으로 애니메이션 효과를 주는 또 다른 Storyboard를 시작합니다.

private void StoryboardC_Completed(object sender, EventArgs e)
{

    Storyboard translationAnimationStoryboard =
        (Storyboard)this.Resources["TranslationAnimationStoryboardResource"];
    translationAnimationStoryboard.Begin(this);
}
Private Sub StoryboardC_Completed(ByVal sender As Object, ByVal e As EventArgs)

    Dim translationAnimationStoryboard As Storyboard = CType(Me.Resources("TranslationAnimationStoryboardResource"), Storyboard)
    translationAnimationStoryboard.Begin(Me)
End Sub

다음은 두 번째 Storyboard를 리소스로 정의하는 태그입니다.

<Page.Resources>
  <Storyboard x:Key="TranslationAnimationStoryboardResource">
    <DoubleAnimation 
      Storyboard.TargetName="MyTranslateTransform"
      Storyboard.TargetProperty="X"
      To="500" Duration="0:0:5" />
  </Storyboard>
</Page.Resources>

Storyboard를 실행할 때 TranslateTransformX 속성이 0에서 350으로 애니메이션 효과를 준 다음 완료된 후 0으로 되돌리고(FillBehavior 설정이 Stop이므로), 그런 다음 0에서 500으로 애니메이션 효과를 줄 것으로 예상할 수 있습니다. 대신 TranslateTransform은 0에서 350으로, 그런 다음 500으로 애니메이션 효과를 줍니다.

그 이유는 WPF 이벤트가 발생하는 순서 때문이고, 속성 값이 캐시되어 속성이 무효화되어야만 다시 계산되기 때문입니다. Completed 이벤트는 루트 타임라인(첫 번째 Storyboard)에 의해 트리거되었기 때문에 먼저 처리됩니다. 이번에는 X 속성이 아직 무효화되지 않았으므로 애니메이션 값을 여전히 반환합니다. 두 번째 Storyboard는 캐시된 값을 시작 값으로 사용하고 애니메이션을 시작합니다.

성능

페이지 외부로 이동한 후에도 애니메이션이 계속 실행됨

실행 중인 애니메이션이 포함된 Page 외부로 이동할 경우 해당 애니메이션은 Page가 가비지 수집될 때까지 계속 재생됩니다. 사용 중인 탐색 시스템에 따라, 빠져 나간 페이지가 제한 없는 시간 동안 메모리에 남아 있으며 해당 애니메이션을 재생하느라 리소스를 계속 사용할 수 있습니다. 페이지에 계속 실행되는("주변") 애니메이션이 포함되어 있을 때 이러한 상황이 가장 두드러지게 나타납니다.

이러한 이유로 Unloaded 이벤트를 사용하여 페이지 외부로 이동할 때는 애니메이션을 제거하는 것이 좋습니다.

애니메이션을 제거하는 방법에는 여러 가지가 있습니다. 다음 기법을 사용하여 Storyboard에 속하는 애니메이션을 제거할 수 있습니다.

애니메이션이 시작된 방법에 관계없이 다음 기법을 사용할 수 있습니다.

  • 특정 속성에서 애니메이션을 제거하려면 BeginAnimation(DependencyProperty, AnimationTimeline) 메서드를 사용하세요. 첫 번째 매개 변수로 애니메이션 효과가 적용 되는 속성을 지정 하 고 null 두 번째입니다. 이렇게 하면 해당 속성에서 모든 애니메이션 클록이 제거됩니다.

속성에 애니메이션 효과를 주는 다양한 방법에 대한 자세한 내용은 속성 애니메이션 기법 개요를 참조하세요.

Compose HandoffBehavior를 사용하여 시스템 리소스 소비

적용 하는 경우는 Storyboard, AnimationTimeline, 또는 AnimationClock 사용 하 여 속성을 ComposeHandoffBehavior모든 Clock 타이밍 시스템 것입니다; 속성을 사용 하 여 이전에 연결 된 개체를 계속 시스템 리소스를 사용 하 자동으로 이러한 클록을 제거 합니다.

많은 수의 시계를 사용 하 여 적용 하는 경우 성능 문제를 방지 하려면 Compose를 완성 한 후 애니메이션된 속성에서 구성 중인 클록을 제거 해야 합니다. 여러 가지 방법으로 클록을 제거할 수 있습니다.

이것은 주로 수명이 긴 개체에 대한 애니메이션에서 문제가 됩니다. 개체가 가비지 수집될 경우 해당 클록도 연결이 끊어지고 가비지가 수집됩니다.

클록 개체에 대 한 자세한 내용은 참조 하세요. 애니메이션 및 타이밍 시스템 개요합니다.

참고 항목