2020년 7월 25일 토요일

WPF - Animation

개요

Winform => TimerBased Animation 을 함. 
그런데 이건 복잡한 계산이 힘듬.

WPF => Property Based Animation 으로 방향을 바꿈.


TimeLine


TimeLine 속성

Duration BeginTime 

TimeSpan.FromSeconds, FromMilliseconds 처럼 여러단위가 가능하다. 
Duration.Forever 을 사용하면 무한을 지정가능
Duration.Automatic 은 1초를 의미함. 디폴트 값임.

SpeedRatio / AccelerationRatio / DecelerationRatio

double 값이 들어감.
Acceleration, Deceleration 은 전체 기간을 0~1 로 한 기준에서 가감속 시작 시점을 말함.

AutoReverse

True 를 하면 애니메이션 종료 후 역재생됨.

FillBehavior

FillBehavior.HoldEnd / Stop 으로 종료 후 마지막 값을 유지할지 정함.
기본값은 HoldEnd

RepeatBehavior

RepeatBehavior.Forever 를 넣으면 무한반복재생 
new RepeatBehavior(5) 로 넣으면 5번만 재생.
new RepeatBehavior(TimeSpan.FromSecond(5)) 를 넣으면 5초동안만 반복함. 

Completed

animation 끝날 때의 이벤트핸들러를 넣으면 됨.
이때 등록한 함수 후에 FillBehavior 관련 함수가 실행됨.


Animation 적용

1
btn01.BeginAnimation(Button.WidthProperty, dblAni);
cs

객체의 BeginAnimation 을 이용해 적용함.
한쪽은 속성 타입, 다른쪽은 Animation 클래스 객체를 넣음.

BeginAnimation 은 덧씌워지는게 아니라 겹쳐서 적용됨. 순차적인 반복.
하지만 dblAni 에 null 을 넣으면 기존 animation 이 사라지고 원상태로 돌아감.

보통 60 프레임으로 적용됨.


Animation 클래스


변환할 값의 Type 별로 Animation 이 있음.

1
2
3
4
5
6
7
8
9
10
DoubleAnimation dblAni = new DoubleAnimation();
dblAni.From = 100;
dblAni.To = 200;
dblAni.Duration = TimeSpan.FromSeconds(2);
dblAni.AutoReverse = true;
dblAni.FillBehavior = FillBehavior.HoldEnd;
dblAni.Completed += dblAni_Complete;
dblAni.BeginTime = TimeSpan.FromSeconds(1);
dblAni.AccelerationRatio = 0.5;
dblAni.SpeedRatio = 1;
cs

위 예시에선 Button.WithProperty 가 Double 타입이므로 DoubleAnimation 객체를 사용함.

From 

지정되지 않으면 현재값을 사용함.

To

종료값

By

From/To 를 By 로 대체할 수 있음. 
By 값은 현재 값에서 더하는 값임.

IsAddictive 

True 를 하면 모든 값은 현재 값을 기준으로 증감하게 됨.


StoryBoard

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Image x:Name="img" 
       Source="https://ww.namu.la/s/2516978e9c2f0a3b309c15f36551d30dd8d81ee814933270c9557c85e9
       MouseEnter="img_MouseEnter">
    <Image.Triggers>
        <EventTrigger RoutedEvent="Image.MouseEnter">
            <EventTrigger.Actions>
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation From="100" To="300" Duration="0:0:3
                             Storyboard.TargetName="img"
                             Storyboard.TargetProperty="Width"/>
                        <DoubleAnimation From="100" To="200" Duration="0:0:0.5"
                                         Storyboard.TargetName="img"
                                         Storyboard.TargetProperty="(Canvas.Left)"/>        
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger.Actions>
        </EventTrigger>
    </Image.Triggers>
</Image>
cs

Trigger 와 함께 자주 쓰임.

위에서 본 DoubleAnimation 이 쓰인 것을 주목.

연관 Property 는 () 로 묶는 것을 주목.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<Window.Resources>
    <Style x:Key="aniGrow">
        <Style.Triggers>
            <Trigger Property="Button.IsPressed" Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="Width" To="200" Duration="0:0:0.5"/>
                        </Storyboard>
                    </BeginStoryboard>
                </Trigger.EnterActions>
                <Trigger.ExitActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="Width" To="100" Duration="0:0:0.5"/>
                        </Storyboard>
                    </BeginStoryboard>
                </Trigger.ExitActions>
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
 
...
 
<Button x:Name="btn01" Content="버튼1" Width="100" Height="50" Click="btn01_Click"
        Style="{StaticResource aniGrow}"/>
cs

위처럼 StroyBoard 는 Style 의 Trigger 와 묶여서 재사용함.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<Window.Triggers>
    <EventTrigger RoutedEvent="Window.Loaded">
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimationUsingPath Storyboard.TargetName="imgUFO"
                                          Storyboard.TargetProperty="(Canvas.Left)"
                                          PathGeometry="{StaticResource path}" Source="X"
                                          Duration="0:0:10" RepeatBehavior="Forever"/>
                <DoubleAnimationUsingPath Storyboard.TargetName="imgUFO"
                                          Storyboard.TargetProperty="(Canvas.Top)"
                                          PathGeometry="{StaticResource path}" Source="Y"
                                          Duration="0:0:10" RepeatBehavior="Forever"/>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</Window.Triggers>
cs

위는 Path 를 경로로 사용하는 DoubleAnimationUsingPath

Animation Control

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<Window.Triggers>
 
    <EventTrigger RoutedEvent="Button.Click" SourceName="btnStart">
        <BeginStoryboard x:Name="stbStart">
            <Storyboard>
                <DoubleAnimation Storyboard.TargetName="img" Storyboard.TargetPro
                                 From="1" To="0" Duration="0:0:10"/>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
    
    <EventTrigger RoutedEvent="Button.Click" SourceName="btnPause">
        <PauseStoryboard BeginStoryboardName="stbStart"/>
    </EventTrigger>
 
    <EventTrigger RoutedEvent="Button.Click" SourceName="btnResume">
        <ResumeStoryboard BeginStoryboardName="stbStart"/>
    </EventTrigger>
 
    <EventTrigger RoutedEvent="Button.Click" SourceName="btnStop">
        <StopStoryboard BeginStoryboardName="stbStart"/>
    </EventTrigger>
 
    <EventTrigger RoutedEvent="Button.Click" SourceName="btnSeek">
        <SeekStoryboard BeginStoryboardName="stbStart" Offset="0:0:5"/>
    </EventTrigger>
 
</Window.Triggers>
cs

BeginStoryboard 

애니메이션 시작

PauseStoryboard

일시정지

ResumeStoryboard

다시시작

StopStoryboard

멈춤

SeekStoryboard

특정 플레이시간으로 점프

CurrentStateInvalidated / CurrentTimeInvalidated

1
2
<Storyboard x:Name="FadeImage" CurrentStateInvalidated="FadeImage_CurrentStateInvalidated" 
    CurrentTimeInvalidated="FadeImage_CurrentTimeInvalidated">
cs


StoryBoard 가 진행될 때 호출되는 이벤트핸들러.


Easing Function

1
2
3
<DoubleAnimation.EasingFunction>
    <ElasticEase EasingMode="EaseIn" Oscillations="2" />
</DoubleAnimation.EasingFunction>
cs

Linear 로 이동하면 자연스럽지 못해서 자연스러운 이동을 하게 해줌.
종류는 많이 있음.

EaseIn / EaseOut 으로 나뉨

EasingFunctionBase 추상클래스를 상속해 커스터마이즈 가능함.


KeyFrame

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<Window.Triggers>
    <EventTrigger RoutedEvent="Window.Loaded">
        <BeginStoryboard>
            <Storyboard>
                <PointAnimationUsingKeyFrames 
                    Storyboard.TargetName="ellipse" Storyboard.TargetProperty="Fill.GradientOrigin" 
                    AutoReverse="True" RepeatBehavior="Forever">
                    <LinearPointKeyFrame Value="0.7, 0.3" KeyTime="0:0:0"/>
                    <LinearPointKeyFrame Value="0.3, 0.7" KeyTime="0:0:1"/>
                    <DiscretePointKeyFrame Value="0.1, 0.1" KeyTime="0:0:2"/>
                    <EasingPointKeyFrame Value="0.6, 0.5" KeyTime="0:0:3">
                        <EasingPointKeyFrame.EasingFunction>
                            <SineEase EasingMode="EaseIn"/>
                        </EasingPointKeyFrame.EasingFunction>
                    </EasingPointKeyFrame>
                </PointAnimationUsingKeyFrames>
                <ColorAnimation 
                    Storyboard.TargetName="ellipse" Storyboard.TargetProperty="Fill.GradientStops[1].C
                    To="Red" Duration="0:0:5"
                    AutoReverse="True" RepeatBehavior="Forever"/>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</Window.Triggers>
cs


성능

1
<Storyboard Timeline.DesiredFrameRate="30">
cs

DesiredFrameRate 로 프레임 조절 가능

1
CompositionTarget.Rendering += CompositionTarget_Rendering;
cs

매번 렌더링마다 호출되는 이벤트핸들러



댓글 없음:

댓글 쓰기

List