WPF之動畫基礎

 之前的總結

01 WPF基礎分享之佈局

02 WPF基礎之路由事件

03 WPF基礎之內容控件

04 WPF基礎之元素綁定

05 WPF基礎之命令

06 WPF基礎之資源

07 WPF基礎之樣式

08 WPF基礎之形狀畫刷和變換

09 WPF基礎之幾何圖形

 動畫部分的內容比較多,會分幾個部分總結,年後會分享高級動畫部分,2019年希望能養成寫博客總結的好習慣,還有之前在印象筆記中總結的東西也陸續寫到博客中,感興趣的小夥伴可以關注下,希望對你有所幫助!

 理解WPF動畫

在許多用戶框架中,開發人員必須從頭構建自己的動畫系統。最常用的技術是結合使用計時器和一些自定義的繪圖邏輯。WPF通過自帶的基於屬性的動畫系統,改變了這種狀況。

 基於時間的動畫

例如需要旋轉Windows窗體應用程序中的About對話框中的一塊文本。下面是構建改解決方案的傳統方法。
  1. 創建週期性觸發的計時器。
  2. 當觸發器出發時,使用事件處理程序計算一些與動畫相關的細節,如新的旋轉角度。然後使窗口的一部分或整個窗口無效。
  3. 不久後,Windows將要求窗口重新繪製自身,觸發自定義的繪圖代碼。
  4. 在自定義繪圖代碼中,渲染旋轉後的文本。
儘管整個基於計時器的解決方案不難實現。但將它集成到普通的應用程序窗口中卻非常麻煩,存在如下問題
  • 繪製像素而不是控件。爲選擇Windows窗體中的文本,需要低級的GDI+繪圖支持。GDI+易於使用,但卻不能與普通的窗口元素很好的相互協調。
  • 假定單一動畫。如果需要運行兩個動畫。就需要重新編寫所有動畫代碼,變得更復雜。
  • 動畫幀率是固定的。計時器決定了幀率,想修改,還可能修改代碼。
  • 複雜動畫需要指數級增長的更復雜的代碼。

 基於屬性的動畫

WPF提供了一個更高級的模型,通過該模型可以只關注動畫的定義,而不必考慮他們的渲染方式。這個模型基於依賴項屬性基礎架構。本質上,WPF動畫只不過是在一段時間間隔內修改依賴項屬性值的一種方式。
例如,爲了增大和縮小按鈕,可在動畫中修改按鈕的寬度。爲使按鈕閃爍,可修改用於按鈕背景的LinearGradientBrush屬性。創建動畫的祕密在於決定需要修改什麼樣的屬性。

 Animotion類

動畫種類,在System.Windows.Media.Animation名稱控件中將發現以下內容。
  • 17個“類型名+Animation”類,這些類使用插值。(在開始值和結束值之間以逐步增加的方式。)
  • 22個“類型名+AnimationUsingKeyFrames”類,這些類使用關鍵幀動畫。(從一個值突然變成另一個值。)
  • 3個“類型名+AnimationUsingPath”類,這些類使用基於路徑的動畫。

 使用代碼創建動畫

<Grid>
        <Button Name="btnShow"  Width="300" Height="50" VerticalAlignment="Center" HorizontalAlignment="Center" Click="Button_Click">
            <Button.Background>
                <LinearGradientBrush>
                    <GradientStop Color="Red" Offset="0"></GradientStop>
                    <GradientStop Color="Blue" Offset="0.5"></GradientStop>
                </LinearGradientBrush>
            </Button.Background>
            Click and Make Me Show</Button>
    </Grid>
 DoubleAnimation withAnimation = new DoubleAnimation();
            withAnimation.From =btnShow.ActualWidth;
            withAnimation.To = this.Width - 30;
            withAnimation.Duration = TimeSpan.FromSeconds(5);
            btnShow.BeginAnimation(Button.WidthProperty, withAnimation);
 

 1.From屬性

Form值是Width屬性的開始值。如果多次單擊按鈕,每次單擊的時,都會將Width屬性重新設置爲160.並且重新開始運行動畫。
在許多情況下可能不希望動畫從最初的From值開始。有兩個常見的原因。
  • 創建能夠被觸發多次,並逐次累加的動畫效果。例如,可能希望創建每次點擊都增大一點的按鈕。
  • 創建可能相互重疊的動畫。例如,可使用MouseEnter事件觸發擴展按鈕的動畫,並使用MouseLeave事件觸發將按鈕縮小爲原尺寸的互補動畫(這通常稱爲"魚眼"效果)。
如上面的效果可以不指定初始值。
DoubleAnimation withAnimation = new DoubleAnimation();
            withAnimation.To = this.Width - 30;
            withAnimation.Duration = TimeSpan.FromSeconds(5);
            btnShow.BeginAnimation(Button.WidthProperty, withAnimation);
ActualWidth和Width屬性的區別,Width屬性反應的是選擇的期望寬度,而AcutalWidth值指示的是最終使用的渲染寬度。如果使用自動佈局,可能根本就沒有設置硬編碼的Width值,所Width屬性只會返回Double.NaN值,開始動畫時會拋異常。

 2.To屬性

就像可省略From屬性一樣也可省略To屬性。

 3.By屬性

By屬性用於創建按鈕設置的數量改變值的動畫,而不是目標改變值。
          
  DoubleAnimation withAnimation = new DoubleAnimation();
            withAnimation.By = 10;
            withAnimation.Duration = TimeSpan.FromSeconds(5);
            btnShow.BeginAnimation(Button.WidthProperty, withAnimation);

 4.Duration屬性

在動畫開始時刻和結束時刻之間的時間間隔。

 Timeline類

動畫類繼承自Timeline抽象類,有三個主要子類,播放音頻或視頻文件時使用的MediaTimeline類,基於屬性的AnimationTimeline類,允許同步時間線並控制他們的播放速度的TimelineGroup類。
Timeline類屬性
 
名稱
說明
BeginTime 設置被添加到動畫開始之前的延遲時間(TimeSpan類型)。這一延遲被加到總時間,所以具有5秒延遲的5秒動畫,總時間是10秒。當按順序應用效果不同的動畫時,BeginTime屬性是很有用的。
Duration 使用Duration對象設置動畫從開始到結束的時間。
SpeedRadio 提高或減慢動畫速度。通常,SpeedRadio屬性值是1。如果增加該屬性值,動畫會加快(例如,如果SpeedRadio屬性的值爲5,動畫的速度會變爲原來的5倍);如果減小該屬性的值,動畫會變慢。可通過改變動畫的Duration屬性值得到相同的結果。當應用BeginTime延遲時,不考慮SpeedRadio屬性的值。
AccelerationRadio
DecelerationRadio
使動畫不是線性的,從開始時較慢,然後增速(通過增加AccelarationRadio屬性值);或者結束時降低速度(通過增加Decelaration屬性值。)這兩個值都在0到1之間。初始值都是0.
AutoReverse 如果爲True,當動畫完成時會自動反向播放,返回到原始值。這也會使動畫的運行時間加倍。如果增加SpeedRatio屬性值,就會應用到最初的動畫播放以及反向的動畫播放。BeginTime屬性值只應用於動畫的開始-不延遲反向動畫。
FillBehavior 決定當動畫結束時如何操作。通常,可將屬性值保持爲固定的結算值(FillBehavior.HoldEnd),但是也可以選擇將屬性值返回原來的數值(FillBehavior.Stop)
RepeatBehavior 通過該屬性,可以使用指定的次數或時間間隔重複動畫。
  withAnimation.RepeatBehavior = new RepeatBehavior(3);//重複3個
            withAnimation.RepeatBehavior = new RepeatBehavior(TimeSpan.FromSeconds(13));//重複13秒
            withAnimation.RepeatBehavior = RepeatBehavior.Forever;//一直重複

 故事板

WPF動畫使用了極少數的屬性設置信息,如開始值、結束值以及持續時間。非常適合於XAML。不是很清晰的是如何爲特定的事件和屬性關聯動畫,以及如何在正確的時間觸發動畫。
在所有聲明式動畫中都會用到如下兩個要素:
  • 故事板。故事板是BeginAnimation()方法的XAML等價物。通過故事板將動畫指定到合適的元素和屬性。
  • 事件觸發器。時間觸發器相應屬性變化或事件,並控制故事板。
故事板是增強的時間線,可用來分組多個動畫,具有控制動畫播放的能力,暫停、停止以及改變播放位置。通過TargetProperty和TargetName屬性值指向某個元素和特定屬性。
 <Button Padding="10" Name="cmdGrow" Height="40" Width="160" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button.Triggers>
                <EventTrigger RoutedEvent="Button.Click">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation AutoReverse="True" Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width" Duration="0:0:5" To=" 300"></DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>
            </Button.Triggers>
            <Button.Content>
                Click Me And Make Me Grow
            </Button.Content>
        </Button>
 
Storyboard.TargetProperty 如果沒有提供類的名稱,故事板使用父元素。如果希望設置附加屬性,用如下語法。
Storyboard.TargetProperty="(Canvas.Left)"

 樣式觸發器

 
<Window.Resources>
        <Style x:Key="GrowButtonStyle">
            <Style.Triggers>
                <Trigger Property="Button.IsPressed" Value="True">
                    <Trigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation AutoReverse="True"  Storyboard.TargetProperty="Width" Duration="0:0:5" To=" 300"></DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.EnterActions>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <Button Padding="10"  Style="{StaticResource GrowButtonStyle}" Name="cmdGrow" Height="40" Width="160" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button.Content>
                Click Me And Make Me Grow
            </Button.Content>
        </Button>
    </Grid>
</Window>

 同步的動畫

 
<EventTrigger RoutedEvent="Button.Click">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation AutoReverse="True" Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width" Duration="0:0:5" To=" 300"></DoubleAnimation>
                                <DoubleAnimation AutoReverse="True" Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Height" Duration="0:0:5" To=" 300"></DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>

 控制播放

一旦創建故事板,就可以用其他動作控制故事板。這些動作都繼承自ControllableStoryboardAction類。
 
 
名稱
說明
PauseStoryboard 停止播放動畫並且保持其當前位置。
ResumeStroyboard 恢復播放暫停的動畫。
StopStoryboard 停止播放動畫,並將動畫時鐘重新設置到開始位置。
SeekStoryboard 跳到動畫線中的特定位置。如果動畫正在播放,就繼續從新位置播放。如果動畫是暫停的,就繼續保持暫停。
SetStoryboardSpeedRadio 改變整個故事板的SpeedRatio屬性值。
SkipStoryboardToFill 講故事板移到時間線的終點。
RemoveStoryboard 移除故事板,停止所有在運行的動畫並將屬性返回原來的、最後一次設置的值。
白天過度到黑夜動畫效果
 
    <Window.Triggers>
        <EventTrigger SourceName="cmdStart" RoutedEvent="Button.Click">
            <BeginStoryboard Name="fadeStoryboardBegin">
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetName="imgDay" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:10"></DoubleAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger SourceName="cmdPause" RoutedEvent="Button.Click">
            <PauseStoryboard BeginStoryboardName="fadeStoryboardBegin"></PauseStoryboard>
        </EventTrigger>
        <EventTrigger SourceName="cmdResume" RoutedEvent="Button.Click">
            <RemoveStoryboard BeginStoryboardName="fadeStoryboardBegin"></RemoveStoryboard>
        </EventTrigger>
        <EventTrigger SourceName="cmdStop" RoutedEvent="Button.Click">
            <StopStoryboard BeginStoryboardName="fadeStoryboardBegin"></StopStoryboard>
        </EventTrigger>
        <EventTrigger SourceName="cmdMiddle" RoutedEvent="Button.Click">
            <SeekStoryboard BeginStoryboardName="fadeStoryboardBegin" Offset="0:0:5"></SeekStoryboard>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="60"></RowDefinition>
        </Grid.RowDefinitions>
        <Image Source="http://pic28.photophoto.cn/20130805/0034034811466737_b.jpg"></Image>
        <Image Source="http://img.pconline.com.cn/images/upload/upc/tx/itbbs/1608/11/c3/25402170_1470872089662_mthumb.jpg" Name="imgDay"></Image>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="5" Grid.Row="1" Height="60">
            <Button Name="cmdStart" Height="20" Width="50">Start</Button>
            <Button Name="cmdPause" Height="20" Width="50">Pause</Button>
            <Button Name="cmdResume" Height="20" Width="50">Resume</Button>
            <Button Name="cmdStop" Height="20" Width="50">Stop</Button>
            <Button Name="cmdMiddle" Height="20" Width="50">Move To Middle</Button>
        </StackPanel>
    </Grid>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章