本文目錄
使用動畫,是增強用戶體驗的一種有效的手段。合理的動畫,可以讓應用程序的界面看起來更加自然、真實、流暢、舒適,更有效地向用戶展現信息,用戶也更容易接受。同時也增加了軟件使用的樂趣,提高用戶粘度。(如MSN2011的啟動界面動畫,字體滑動和淡入淡出。)
在以往的程序開發中,如果想構建動畫,需要定時器和自定義的繪圖元素,並讓這些繪圖元素根據定時器做出相應的改變,以實現動畫效果,開發難度和工作量都是很高的。並且這些動畫的拓展性和靈活性一般很弱,代碼量和復雜度卻很大。而在WPF中,可以使用聲明的方式構建動畫,甚至不需要任何后台代碼,就可以實現動畫效果。WPF提供的動畫模型和強大的類庫,讓一般動畫的實現,都變得輕而易舉。在WPF中,創建更加復雜的動畫,甚至也可以使用設計工具或第三方工具在XAML中實現。所以,需要的更多的,可能不是代碼量,而是你的想象力!
本文將介紹WPF 中三種基本動畫,線性插值、關鍵幀和路徑動畫。
在 System.Windows.Media.Animation 這個命名空間中,包含了三種動畫類:線性插值動畫類(17個)、關鍵幀動畫(22個)、路徑動畫(3個)。
在C#代碼中使用Animation類,需要引入命名空間:System.Windows.Media.Animation
using System.Windows.Media.Animation;
該動畫表現為,元素的某個屬性,在開始值和結束值之間逐步增加,是一種線性插值的過程。比如,實現一個按鈕的淡入效果,讓它的透明度Opacity在0~1之間線性增長,就可以實現預期效果。
以下是 System.Windows.Media.Animation 命名空間中,17個線性插值動畫類。
ByteAnimation
ColorAnimation
DecimalAnimation
DoubleAnimation
Int16Animation
Int32Animation
Int64Animation
Point3DAnimation
PointAnimation
QuaternionAnimation
RectAnimation
Rotation3DAnimation
SingleAnimation
SizeAnimation
ThicknessAnimation
Vector3DAnimation
VectorAnimation
示例1:以 DoubleAnimation 為例,實現文字的淡入效果。
在XAML中可以直接定義動畫,以下示例是以后台代碼形式實現的動畫。
XAML
<TextBlock Height="50" Width="220" Foreground="#326939" FontSize="36" Name="textBlock1" Text="文字淡入效果"/>
CS
DoubleAnimation da = new DoubleAnimation(); da.From = 0; //起始值 da.To = 1; //結束值 da.Duration = TimeSpan.FromSeconds(3); //動畫持續時間 this.textBlock1.BeginAnimation(TextBlock.OpacityProperty, da);//開始動畫
示例2:利用 ThicknessAnimation ,實現元素平移效果。
XMAL
<TextBlock Height="50" Foreground="#326939" Margin="0,100,0,0" FontSize="36" Name="textBlock1" Text="文字平移"/>
CS
//文字平移,Margin屬性是Thickness類型,選擇ThicknessAnimation ThicknessAnimation ta = new ThicknessAnimation(); ta.From = new Thickness(0, 100, 0, 0); //起始值 ta.To = new Thickness(240, 100, 0, 0); //結束值 ta.Duration = TimeSpan.FromSeconds(3); //動畫持續時間 this.textBlock1.BeginAnimation(TextBlock.MarginProperty, ta);//開始動畫
關鍵幀動畫是以時間為節點,在指定時間節點上,屬性達到某個值。
以下是 System.Windows.Media.Animation 命名空間中,22個關鍵幀動畫類。
BooleanAnimationUsingKeyFrames
ByteAnimationUsingKeyFrames
CharAnimationUsingKeyFrames
ColorAnimationUsingKeyFrames
DecimalAnimationUsingKeyFrames
DoubleAnimationUsingKeyFrames
Int16AnimationUsingKeyFrames
Int32AnimationUsingKeyFrames
Int64AnimationUsingKeyFrames
MatrixAnimationUsingKeyFrames
ObjectAnimationUsingKeyFrames
Point3DAnimationUsingKeyFrames
PointAnimationUsingKeyFrames
QuaternionAnimationUsingKeyFrames
RectAnimationUsingKeyFrames
Rotation3DAnimationUsingKeyFrames
SingleAnimationUsingKeyFrames
SizeAnimationUsingKeyFrames
StringAnimationUsingKeyFrames
ThicknessAnimationUsingKeyFrames
Vector3DAnimationUsingKeyFrames
VectorAnimationUsingKeyFrames
示例3:Border寬度的關鍵幀動畫
XAML
<Border Height="32" Width="0" Background="#326939" Name="border1"/>
CS
//Border長度關鍵幀動畫 DoubleAnimationUsingKeyFrames dak = new DoubleAnimationUsingKeyFrames(); //關鍵幀定義 dak.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0)))); dak.KeyFrames.Add(new LinearDoubleKeyFrame(240, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(3)))); dak.KeyFrames.Add(new LinearDoubleKeyFrame(240, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(6)))); dak.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(9)))); dak.BeginTime = TimeSpan.FromSeconds(2);//從第2秒開始動畫 dak.RepeatBehavior = new RepeatBehavior(3);//動畫重復3次 //開始動畫 this.border1.BeginAnimation(Border.WidthProperty, dak);
(程序運行時開始計時,第0秒)
0~5:動畫尚未開始;
5~8:border1寬度從0增加到240;
8~11:border1寬度保持240不變;
11~14:border1寬度從240減少到0;
14-17:又從0增加到240……(即5~14的過程循環3次)
基於路徑的動畫,比起前兩種更加專業一些。它的表現方式是,修改數值使其符合PathGeometry對象描述的形狀,並且讓元素沿着路徑移動。以下是 System.Windows.Media.Animation 命名空間中,3個路徑動畫類。
DoubleAnimationUsingPath
MatrixAnimationUsingPath
PointAnimationUsingPath
示例4:基於路徑動畫的演示
XMAL(該動畫是在XAML中定義,使用事件觸發器,窗體加載時開始動畫)
<Window x:Class="WpfApplication9.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="360" Width="480"> <Window.Resources> <!--路徑資源--> <PathGeometry x:Key="path"> <PathFigure IsClosed="True"> <ArcSegment Point="200,200" Size="30,10" SweepDirection="Clockwise"></ArcSegment> <ArcSegment Point="300,200" Size="5,5"></ArcSegment> </PathFigure> </PathGeometry> </Window.Resources> <!---事件觸發器,窗體加載時動畫開始,周期6秒,無限循環--> <Window.Triggers> <EventTrigger RoutedEvent="Window.Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimationUsingPath Storyboard.TargetName="image" Storyboard.TargetProperty="(Canvas.Left)" PathGeometry="{StaticResource path}" Duration="0:0:6" RepeatBehavior="Forever" Source="X"></DoubleAnimationUsingPath> <DoubleAnimationUsingPath Storyboard.TargetName="image" Storyboard.TargetProperty="(Canvas.Top)" PathGeometry="{StaticResource path}" Duration="0:0:6" RepeatBehavior="Forever" Source="Y"></DoubleAnimationUsingPath> </Storyboard> </BeginStoryboard> </EventTrigger> </Window.Triggers> <Canvas> <!--顯示路徑--> <Path Margin="30" Stroke="#ddd" Data="{StaticResource path}"></Path> <!--動畫元素--> <Image Name="image" Source="me.png" Width="48" Height="48" /> </Canvas> </Window>
我的頭像將沿着曲線路徑進行移動,由於RepeatBehavior屬性設置為Forever,則動畫將無限循環。
====================================================
WPF翻轉動畫
小丫頭比較調皮,為了做個東東來哄一下小丫頭,我想到了做一個簡單的三維翻轉動畫。在登錄QQ 2013 的時候,我看到登錄窗口也有類似的動畫。
在WPF中要翻轉對象,估計是得用三維變換,所以我用到了AxisAngleRotation3D,讓圖形繞着Z軸來旋轉。
先看看效果。
是的,就是這樣的效果,在XAML中,由於涉及三維圖形,我先做了兩個用戶控件,作為正面和背面,然后讓它旋轉。
設計完用戶控件后,就在主窗口上放一個Viewport3D控件,這個是必須的,它是三維模型的容器,如果不用就不知道怎么弄出三維圖形來了。具體請看下面的XAML:
- <Window x:Class="翻轉.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="MainWindow" Height="420" Width="650"
- xmlns:local="clr-namespace:翻轉"
- WindowStyle="None"
- ResizeMode="NoResize"
- AllowsTransparency="True"
- Background="Transparent"
- WindowStartupLocation="CenterScreen">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="*"/>
- <RowDefinition Height="auto"/>
- </Grid.RowDefinitions>
- <Viewport3D Grid.Row="0" Margin="3">
- <Viewport3D.Camera>
- <PerspectiveCamera Position="0 0 800" LookDirection="0 0 -1" NearPlaneDistance="100"/>
- </Viewport3D.Camera>
- <Viewport3D.Children>
- <ContainerUIElement3D>
- <Viewport2DVisual3D>
- <Viewport2DVisual3D.Geometry>
- <MeshGeometry3D Positions="-200 150 0 -200 -150 0 200 -150 0 200 150 0" TriangleIndices="0 1 2 0 2 3" TextureCoordinates="0 0 0 1 1 1 1 0"/>
- </Viewport2DVisual3D.Geometry>
- <Viewport2DVisual3D.Material>
- <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True"/>
- </Viewport2DVisual3D.Material>
- <Viewport2DVisual3D.Visual>
- <local:UcSample1 Width="400" Height="300"/>
- </Viewport2DVisual3D.Visual>
- </Viewport2DVisual3D>
- <Viewport2DVisual3D>
- <Viewport2DVisual3D.Geometry>
- <MeshGeometry3D Positions="200 150 0 200 -150 0 -200 -150 0 -200 150 0" TriangleIndices="0 1 2 0 2 3" TextureCoordinates="0 0 0 1 1 1 1 0"/>
- </Viewport2DVisual3D.Geometry>
- <Viewport2DVisual3D.Material>
- <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True"/>
- </Viewport2DVisual3D.Material>
- <Viewport2DVisual3D.Visual>
- <local:UcSample2 Width="400" Height="300"/>
- </Viewport2DVisual3D.Visual>
- </Viewport2DVisual3D>
- <!-- 三維變換 -->
- <ContainerUIElement3D.Transform>
- <RotateTransform3D CenterX="0.5" CenterY="0.5" CenterZ="0.5">
- <RotateTransform3D.Rotation>
- <AxisAngleRotation3D x:Name="axr" Angle="0" Axis="0 1 0"/>
- </RotateTransform3D.Rotation>
- </RotateTransform3D>
- </ContainerUIElement3D.Transform>
- </ContainerUIElement3D>
- <ModelVisual3D>
- <ModelVisual3D.Content>
- <DirectionalLight Color="Transparent"/>
- </ModelVisual3D.Content>
- </ModelVisual3D>
- </Viewport3D.Children>
- </Viewport3D>
- <StackPanel Grid.Row="1" Margin="0,5,0,6" Orientation="Horizontal" HorizontalAlignment="Center">
- <Button Padding="25,5" Content="向前" Click="OnClick"/>
- <Button Padding="25,5" Content="向后" Click="OnClick" Margin="12,0,0,0"/>
- <Button Padding="25,5" Content="關閉" Click="OnClick" Margin="12,0,0,0"/>
- </StackPanel>
- </Grid>
- </Window>
<Window x:Class="翻轉.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="420" Width="650" xmlns:local="clr-namespace:翻轉" WindowStyle="None" ResizeMode="NoResize" AllowsTransparency="True" Background="Transparent" WindowStartupLocation="CenterScreen"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Viewport3D Grid.Row="0" Margin="3"> <Viewport3D.Camera> <PerspectiveCamera Position="0 0 800" LookDirection="0 0 -1" NearPlaneDistance="100"/> </Viewport3D.Camera> <Viewport3D.Children> <ContainerUIElement3D> <Viewport2DVisual3D> <Viewport2DVisual3D.Geometry> <MeshGeometry3D Positions="-200 150 0 -200 -150 0 200 -150 0 200 150 0" TriangleIndices="0 1 2 0 2 3" TextureCoordinates="0 0 0 1 1 1 1 0"/> </Viewport2DVisual3D.Geometry> <Viewport2DVisual3D.Material> <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True"/> </Viewport2DVisual3D.Material> <Viewport2DVisual3D.Visual> <local:UcSample1 Width="400" Height="300"/> </Viewport2DVisual3D.Visual> </Viewport2DVisual3D> <Viewport2DVisual3D> <Viewport2DVisual3D.Geometry> <MeshGeometry3D Positions="200 150 0 200 -150 0 -200 -150 0 -200 150 0" TriangleIndices="0 1 2 0 2 3" TextureCoordinates="0 0 0 1 1 1 1 0"/> </Viewport2DVisual3D.Geometry> <Viewport2DVisual3D.Material> <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True"/> </Viewport2DVisual3D.Material> <Viewport2DVisual3D.Visual> <local:UcSample2 Width="400" Height="300"/> </Viewport2DVisual3D.Visual> </Viewport2DVisual3D> <!-- 三維變換 --> <ContainerUIElement3D.Transform> <RotateTransform3D CenterX="0.5" CenterY="0.5" CenterZ="0.5"> <RotateTransform3D.Rotation> <AxisAngleRotation3D x:Name="axr" Angle="0" Axis="0 1 0"/> </RotateTransform3D.Rotation> </RotateTransform3D> </ContainerUIElement3D.Transform> </ContainerUIElement3D> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight Color="Transparent"/> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> </Viewport3D> <StackPanel Grid.Row="1" Margin="0,5,0,6" Orientation="Horizontal" HorizontalAlignment="Center"> <Button Padding="25,5" Content="向前" Click="OnClick"/> <Button Padding="25,5" Content="向后" Click="OnClick" Margin="12,0,0,0"/> <Button Padding="25,5" Content="關閉" Click="OnClick" Margin="12,0,0,0"/> </StackPanel> </Grid> </Window>
里面還有幾個按鈕,我是通過單擊按鈕來控制動畫的,所以,后面還要寫必要的處理代碼,生成動畫。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Navigation;
- using System.Windows.Shapes;
- using System.Windows.Media.Media3D;
- using System.Windows.Media.Animation;
- namespace 翻轉
- {
- /// <summary>
- /// MainWindow.xaml 的交互邏輯
- /// </summary>
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- }
- private void OnClick(object sender, RoutedEventArgs e)
- {
- Button btn = e.OriginalSource as Button;
- if (btn != null)
- {
- string s = btn.Content.ToString();
- if (s == "關閉")
- {
- this.Close();
- }
- DoubleAnimation da = new DoubleAnimation();
- da.Duration = new Duration(TimeSpan.FromSeconds(1));
- if (s == "向前")
- {
- da.To = 0d;
- }
- else if (s == "向后")
- {
- da.To = 180d;
- }
- this.axr.BeginAnimation(AxisAngleRotation3D.AngleProperty, da);
- }
- }
- }
- }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Media.Media3D; using System.Windows.Media.Animation; namespace 翻轉 { /// <summary> /// MainWindow.xaml 的交互邏輯 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void OnClick(object sender, RoutedEventArgs e) { Button btn = e.OriginalSource as Button; if (btn != null) { string s = btn.Content.ToString(); if (s == "關閉") { this.Close(); } DoubleAnimation da = new DoubleAnimation(); da.Duration = new Duration(TimeSpan.FromSeconds(1)); if (s == "向前") { da.To = 0d; } else if (s == "向后") { da.To = 180d; } this.axr.BeginAnimation(AxisAngleRotation3D.AngleProperty, da); } } } }
當圖形繞Z軸轉0度,就表示是正面,如果為180度,就轉到反面。我們在聲明Viewport2DVisual3D.Geometry的坐標模型,即三角型疊加模型,要注意點逆時針方向順序來定義,如果弄反了,那么圖形就跑到模型的背面去了。因此,正面圖形和背面圖形的點的方向是剛好相反的。
三維的東西不太好解釋,所以我稍后把代碼上傳,以供參考。
下載地址:http://download.csdn.net/detail/tcjiaan/5243065
以下是用WPF實現的的一個窗口,為了使演示變得簡單,我在窗口中只放了一個按鈕。如下圖所示:
但我們今天的主題是窗口啟動時和關閉時都展示動畫,如何進行動畫處理,我以前寫過一些WPF相關的文章。
要將窗口進行自定義,首先我們要去掉默認窗口的邊框、背景色和標題欄。
這個不難,在WPF中,要把窗體徹底透明,只要做三件事即可:
(1)設置WindowStyle屬性為None。
(2)AllowsTransparency屬性設置為true。
(3)Background屬性為Transparent。
為了使窗體易於控件,可以考慮設置ResizeMode="NoResize"。
窗口變成了透明,這使得窗口的整個區域就需要我們自己來設計了。
為了使自定義的窗口也有邊框,在最外層,我們應該考慮使用Border,然后里面放一個Grid,這個Grid划分為兩行,第一行作為標題欄,第二行作為窗口的客戶區域。
- <Border x:Name="wb" CornerRadius="5" BorderThickness="3" BorderBrush="#FF1A55AA">
- <Border.Background>
- <LinearGradientBrush EndPoint="0.8,1" StartPoint="0.33,0">
- <GradientStop Color="#FF50B3E2" Offset="0"/>
- <GradientStop Color="#FF084168" Offset="1"/>
- </LinearGradientBrush>
- </Border.Background>
- <Grid x:Name="root" >
- <Grid.RowDefinitions>
- <RowDefinition Height="auto"/>
- <RowDefinition Height="*"/>
- </Grid.RowDefinitions>
- ……
- </Grid>
- </Border>
<Border x:Name="wb" CornerRadius="5" BorderThickness="3" BorderBrush="#FF1A55AA"> <Border.Background> <LinearGradientBrush EndPoint="0.8,1" StartPoint="0.33,0"> <GradientStop Color="#FF50B3E2" Offset="0"/> <GradientStop Color="#FF084168" Offset="1"/> </LinearGradientBrush> </Border.Background> <Grid x:Name="root" > <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> …… </Grid> </Border>
以上是窗口的大致框架。
接下來就是對最外層的Border進行剪裁,即設置它的Clip屬性。
- <Border x:Name="wb" CornerRadius="5" BorderThickness="3" BorderBrush="#FF1A55AA">
- <Border.Background>
- <LinearGradientBrush EndPoint="0.8,1" StartPoint="0.33,0">
- <GradientStop Color="#FF50B3E2" Offset="0"/>
- <GradientStop Color="#FF084168" Offset="1"/>
- </LinearGradientBrush>
- </Border.Background>
- <Border.Clip>
- <GeometryGroup FillRule="Nonzero">
- <RectangleGeometry x:Name="r1" Rect="0,50,1000,100"/>
- <RectangleGeometry x:Name="r2" Rect="0,220,1000,100"/>
- <RectangleGeometry x:Name="r3" Rect="50,0,90,1000"/>
- <RectangleGeometry x:Name="r4" Rect="360,0,160,1000"/>
- </GeometryGroup>
- </Border.Clip>
- <Grid x:Name="root" >
- <Grid.RowDefinitions>
- <RowDefinition Height="auto"/>
- <RowDefinition Height="*"/>
- </Grid.RowDefinitions>
- ……
- </Grid>
- </Border>
<Border x:Name="wb" CornerRadius="5" BorderThickness="3" BorderBrush="#FF1A55AA"> <Border.Background> <LinearGradientBrush EndPoint="0.8,1" StartPoint="0.33,0"> <GradientStop Color="#FF50B3E2" Offset="0"/> <GradientStop Color="#FF084168" Offset="1"/> </LinearGradientBrush> </Border.Background> <Border.Clip> <GeometryGroup FillRule="Nonzero"> <RectangleGeometry x:Name="r1" Rect="0,50,1000,100"/> <RectangleGeometry x:Name="r2" Rect="0,220,1000,100"/> <RectangleGeometry x:Name="r3" Rect="50,0,90,1000"/> <RectangleGeometry x:Name="r4" Rect="360,0,160,1000"/> </GeometryGroup> </Border.Clip> <Grid x:Name="root" > <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> …… </Grid> </Border>
那么,通過這四個矩形的裁剪,窗口會變成什么模樣呢。看下圖。
下面就是窗口的啟動動畫,通過對這四個矩形進行動畫處理,在窗體的Loaded事件中播放動畫,當動畫播放完成時,再把這些Clip去掉,即設為null。
- <Window.Resources>
- <Storyboard x:Key="start">
- <RectAnimation Storyboard.TargetName="r1" Storyboard.TargetProperty="Rect"
- Duration="0:0:6" To="0,0,900,900"/>
- <RectAnimation Storyboard.TargetName="r2" Storyboard.TargetProperty="Rect"
- Duration="0:0:5" To="20,20,700,800"/>
- <RectAnimation Storyboard.TargetName="r3" Storyboard.TargetProperty="Rect"
- Duration="0:0:6" To="85,0,850,700"/>
- <RectAnimation Storyboard.TargetName="r4" Storyboard.TargetProperty="Rect"
- Duration="0:0:6" To="0,250,800,700"/>
- <DoubleAnimation Storyboard.TargetName="wb" Storyboard.TargetProperty="Opacity"
- From="0.2" To="1" Duration="0:0:6"/>
- </Storyboard>
- <Storyboard x:Key="end">
- <DoubleAnimation Storyboard.TargetName="wb" Storyboard.TargetProperty="Opacity"
- Duration="0:0:5" From="1" To="0"/>
- <DoubleAnimation Storyboard.TargetName="rt" Storyboard.TargetProperty="Angle"
- Duration="0:0:5" From="0" To="720"/>
- <DoubleAnimation Storyboard.TargetName="sct" Storyboard.TargetProperty="ScaleX"
- Duration="0:0:5" From="1" To="0.3"/>
- <DoubleAnimation Storyboard.TargetName="sct" Storyboard.TargetProperty="ScaleY"
- Duration="0:0:5" From="1" To="0.1"/>
- </Storyboard>
- </Window.Resources>
<Window.Resources> <Storyboard x:Key="start"> <RectAnimation Storyboard.TargetName="r1" Storyboard.TargetProperty="Rect" Duration="0:0:6" To="0,0,900,900"/> <RectAnimation Storyboard.TargetName="r2" Storyboard.TargetProperty="Rect" Duration="0:0:5" To="20,20,700,800"/> <RectAnimation Storyboard.TargetName="r3" Storyboard.TargetProperty="Rect" Duration="0:0:6" To="85,0,850,700"/> <RectAnimation Storyboard.TargetName="r4" Storyboard.TargetProperty="Rect" Duration="0:0:6" To="0,250,800,700"/> <DoubleAnimation Storyboard.TargetName="wb" Storyboard.TargetProperty="Opacity" From="0.2" To="1" Duration="0:0:6"/> </Storyboard> <Storyboard x:Key="end"> <DoubleAnimation Storyboard.TargetName="wb" Storyboard.TargetProperty="Opacity" Duration="0:0:5" From="1" To="0"/> <DoubleAnimation Storyboard.TargetName="rt" Storyboard.TargetProperty="Angle" Duration="0:0:5" From="0" To="720"/> <DoubleAnimation Storyboard.TargetName="sct" Storyboard.TargetProperty="ScaleX" Duration="0:0:5" From="1" To="0.3"/> <DoubleAnimation Storyboard.TargetName="sct" Storyboard.TargetProperty="ScaleY" Duration="0:0:5" From="1" To="0.1"/> </Storyboard> </Window.Resources>
上面的資源中,包含兩個動畫,后面一個是窗口關閉時的動畫。
另外,我們的窗口還需要兩個小按鈕,就是標題欄上方的“最小化”和“關閉”按鈕,用Button即可,不過我們要為Button類自定義一下控件模板。
- <Application.Resources>
- <Style TargetType="{x:Type Button}" x:Key="captionButtonStyle">
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="{x:Type Button}">
- <Grid>
- <VisualStateManager.VisualStateGroups>
- <VisualStateGroup x:Name="CommonStates">
- <VisualState x:Name="Normal"/>
- <VisualState x:Name="MouseOver">
- <Storyboard>
- <DoubleAnimation Storyboard.TargetName="lbd"
- Storyboard.TargetProperty="Opacity"
- Duration="0:0:0.3"
- To="1"/>
- </Storyboard>
- </VisualState>
- <VisualState x:Name="Pressed">
- <Storyboard>
- <DoubleAnimation Storyboard.TargetName="lbd"
- Storyboard.TargetProperty="Opacity"
- Duration="0"
- To="1"/>
- </Storyboard>
- </VisualState>
- <VisualState x:Name="Disabled">
- <Storyboard>
- <DoubleAnimation Storyboard.TargetName="rctdisable"
- Storyboard.TargetProperty="Opacity"
- Duration="0" To="0.45"/>
- </Storyboard>
- </VisualState>
- </VisualStateGroup>
- <VisualStateGroup x:Name="FocusStates">
- <VisualState x:Name="Focused"/>
- </VisualStateGroup>
- <VisualStateGroup x:Name="ValidationStates">
- <VisualState x:Name="InvalidFocused"/>
- <VisualState x:Name="InvalidUnfocused"/>
- </VisualStateGroup>
- </VisualStateManager.VisualStateGroups>
- <Border x:Name="lbd" BorderThickness="0" Background="{TemplateBinding Background}" CornerRadius="2" Opacity="0"/>
- <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}" />
- <Rectangle x:Name="rctdisable" Opacity="0" Fill="#FFF4F8F9"/>
- </Grid>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- <Setter Property="FontFamily" Value="Segoe UI Symbol"/>
- <Setter Property="FontSize" Value="14"/>
- <Setter Property="Foreground" Value="White"/>
- <Setter Property="Padding" Value="3"/>
- </Style>
- <Style x:Key="minCaptionButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource captionButtonStyle}">
- <Setter Property="Content" Value=""/>
- <Setter Property="Background">
- <Setter.Value>
- <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
- <GradientStop Color="#BFFFFFFF"/>
- <GradientStop Offset="1"/>
- </LinearGradientBrush>
- </Setter.Value>
- </Setter>
- </Style>
- <Style x:Key="closeCaptionButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource captionButtonStyle}">
- <Setter Property="Content" Value=""/>
- <Setter Property="Background">
- <Setter.Value>
- <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
- <GradientStop Color="#FFEA1E1E" Offset="0"/>
- <GradientStop Color="#CCF5544C" Offset="0.7"/>
- <GradientStop Offset="1" Color="#33F94949"/>
- </LinearGradientBrush>
- </Setter.Value>
- </Setter>
- </Style>
- </Application.Resources>
<Application.Resources> <Style TargetType="{x:Type Button}" x:Key="captionButtonStyle"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Button}"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"> <Storyboard> <DoubleAnimation Storyboard.TargetName="lbd" Storyboard.TargetProperty="Opacity" Duration="0:0:0.3" To="1"/> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <DoubleAnimation Storyboard.TargetName="lbd" Storyboard.TargetProperty="Opacity" Duration="0" To="1"/> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <DoubleAnimation Storyboard.TargetName="rctdisable" Storyboard.TargetProperty="Opacity" Duration="0" To="0.45"/> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="FocusStates"> <VisualState x:Name="Focused"/> </VisualStateGroup> <VisualStateGroup x:Name="ValidationStates"> <VisualState x:Name="InvalidFocused"/> <VisualState x:Name="InvalidUnfocused"/> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border x:Name="lbd" BorderThickness="0" Background="{TemplateBinding Background}" CornerRadius="2" Opacity="0"/> <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}" /> <Rectangle x:Name="rctdisable" Opacity="0" Fill="#FFF4F8F9"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="FontFamily" Value="Segoe UI Symbol"/> <Setter Property="FontSize" Value="14"/> <Setter Property="Foreground" Value="White"/> <Setter Property="Padding" Value="3"/> </Style> <Style x:Key="minCaptionButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource captionButtonStyle}"> <Setter Property="Content" Value=""/> <Setter Property="Background"> <Setter.Value> <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1"> <GradientStop Color="#BFFFFFFF"/> <GradientStop Offset="1"/> </LinearGradientBrush> </Setter.Value> </Setter> </Style> <Style x:Key="closeCaptionButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource captionButtonStyle}"> <Setter Property="Content" Value=""/> <Setter Property="Background"> <Setter.Value> <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1"> <GradientStop Color="#FFEA1E1E" Offset="0"/> <GradientStop Color="#CCF5544C" Offset="0.7"/> <GradientStop Offset="1" Color="#33F94949"/> </LinearGradientBrush> </Setter.Value> </Setter> </Style> </Application.Resources>
由於這些小按鈕都比較相似,因此,我們先定義一個通用的樣式captionButtonStyle,而后的minCaptionButtonStyle和closeCaptionButtonStyle都是基於這個樣式的。
注意按鈕的字體要使用Segoe UI Symbol,這樣我們可以通過編號來引用一些特殊符號,如關閉按鈕上的 X 。
下面我們回到主窗體,現在我把整個代碼貼出來。
- <Window x:Class="WpfApplication2.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="主窗口" Height="400" Width="600"
- ResizeMode="NoResize" WindowStartupLocation="CenterScreen"
- WindowStyle="None" AllowsTransparency="True" Background="Transparent"
- RenderTransformOrigin="0.5,0.5">
- <Border x:Name="wb" CornerRadius="5" BorderThickness="3" BorderBrush="#FF1A55AA">
- <Border.Background>
- <LinearGradientBrush EndPoint="0.8,1" StartPoint="0.33,0">
- <GradientStop Color="#FF50B3E2" Offset="0"/>
- <GradientStop Color="#FF084168" Offset="1"/>
- </LinearGradientBrush>
- </Border.Background>
- <Border.Clip>
- <GeometryGroup FillRule="Nonzero">
- <RectangleGeometry x:Name="r1" Rect="0,50,1000,100"/>
- <RectangleGeometry x:Name="r2" Rect="0,220,1000,100"/>
- <RectangleGeometry x:Name="r3" Rect="50,0,90,1000"/>
- <RectangleGeometry x:Name="r4" Rect="360,0,160,1000"/>
- </GeometryGroup>
- </Border.Clip>
- <Grid x:Name="root" >
- <Grid.RowDefinitions>
- <RowDefinition Height="auto"/>
- <RowDefinition Height="*"/>
- </Grid.RowDefinitions>
- <Border x:Name="captiobd" Grid.Row="0" Background="#FF1A55AA" Height="32" MouseLeftButtonDown="onLDown">
- <Grid>
- <TextBlock Text="{Binding Path=Title,RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType=Window}}"
- Foreground="White" FontWeight="Bold" FontSize="18" FontFamily="宋體"
- HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="9,0,0,5"/>
- <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Right"
- Margin="0,0,9,11">
- <Button Style="{DynamicResource minCaptionButtonStyle}" Click="onMin" ToolTip="最小化"/>
- <Button Margin="6,0,0,0" Style="{DynamicResource closeCaptionButtonStyle}" Click="onClick" ToolTip="關閉"/>
- </StackPanel>
- </Grid>
- </Border>
- <Button Content="關閉" Grid.Row="1" Click="onClick" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="30" Padding="15" />
- </Grid>
- </Border>
- <Window.RenderTransform>
- <TransformGroup>
- <RotateTransform x:Name="rt" Angle="0"/>
- <ScaleTransform x:Name="sct" ScaleX="1" ScaleY="1"/>
- </TransformGroup>
- </Window.RenderTransform>
- <Window.Resources>
- <Storyboard x:Key="start">
- <RectAnimation Storyboard.TargetName="r1" Storyboard.TargetProperty="Rect"
- Duration="0:0:6" To="0,0,900,900"/>
- <RectAnimation Storyboard.TargetName="r2" Storyboard.TargetProperty="Rect"
- Duration="0:0:5" To="20,20,700,800"/>
- <RectAnimation Storyboard.TargetName="r3" Storyboard.TargetProperty="Rect"
- Duration="0:0:6" To="85,0,850,700"/>
- <RectAnimation Storyboard.TargetName="r4" Storyboard.TargetProperty="Rect"
- Duration="0:0:6" To="0,250,800,700"/>
- <DoubleAnimation Storyboard.TargetName="wb" Storyboard.TargetProperty="Opacity"
- From="0.2" To="1" Duration="0:0:6"/>
- </Storyboard>
- <Storyboard x:Key="end">
- <DoubleAnimation Storyboard.TargetName="wb" Storyboard.TargetProperty="Opacity"
- Duration="0:0:5" From="1" To="0"/>
- <DoubleAnimation Storyboard.TargetName="rt" Storyboard.TargetProperty="Angle"
- Duration="0:0:5" From="0" To="720"/>
- <DoubleAnimation Storyboard.TargetName="sct" Storyboard.TargetProperty="ScaleX"
- Duration="0:0:5" From="1" To="0.3"/>
- <DoubleAnimation Storyboard.TargetName="sct" Storyboard.TargetProperty="ScaleY"
- Duration="0:0:5" From="1" To="0.1"/>
- </Storyboard>
- </Window.Resources>
- </Window>
<Window x:Class="WpfApplication2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="主窗口" Height="400" Width="600" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" WindowStyle="None" AllowsTransparency="True" Background="Transparent" RenderTransformOrigin="0.5,0.5"> <Border x:Name="wb" CornerRadius="5" BorderThickness="3" BorderBrush="#FF1A55AA"> <Border.Background> <LinearGradientBrush EndPoint="0.8,1" StartPoint="0.33,0"> <GradientStop Color="#FF50B3E2" Offset="0"/> <GradientStop Color="#FF084168" Offset="1"/> </LinearGradientBrush> </Border.Background> <Border.Clip> <GeometryGroup FillRule="Nonzero"> <RectangleGeometry x:Name="r1" Rect="0,50,1000,100"/> <RectangleGeometry x:Name="r2" Rect="0,220,1000,100"/> <RectangleGeometry x:Name="r3" Rect="50,0,90,1000"/> <RectangleGeometry x:Name="r4" Rect="360,0,160,1000"/> </GeometryGroup> </Border.Clip> <Grid x:Name="root" > <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Border x:Name="captiobd" Grid.Row="0" Background="#FF1A55AA" Height="32" MouseLeftButtonDown="onLDown"> <Grid> <TextBlock Text="{Binding Path=Title,RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType=Window}}" Foreground="White" FontWeight="Bold" FontSize="18" FontFamily="宋體" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="9,0,0,5"/> <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="0,0,9,11"> <Button Style="{DynamicResource minCaptionButtonStyle}" Click="onMin" ToolTip="最小化"/> <Button Margin="6,0,0,0" Style="{DynamicResource closeCaptionButtonStyle}" Click="onClick" ToolTip="關閉"/> </StackPanel> </Grid> </Border> <Button Content="關閉" Grid.Row="1" Click="onClick" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="30" Padding="15" /> </Grid> </Border> <Window.RenderTransform> <TransformGroup> <RotateTransform x:Name="rt" Angle="0"/> <ScaleTransform x:Name="sct" ScaleX="1" ScaleY="1"/> </TransformGroup> </Window.RenderTransform> <Window.Resources> <Storyboard x:Key="start"> <RectAnimation Storyboard.TargetName="r1" Storyboard.TargetProperty="Rect" Duration="0:0:6" To="0,0,900,900"/> <RectAnimation Storyboard.TargetName="r2" Storyboard.TargetProperty="Rect" Duration="0:0:5" To="20,20,700,800"/> <RectAnimation Storyboard.TargetName="r3" Storyboard.TargetProperty="Rect" Duration="0:0:6" To="85,0,850,700"/> <RectAnimation Storyboard.TargetName="r4" Storyboard.TargetProperty="Rect" Duration="0:0:6" To="0,250,800,700"/> <DoubleAnimation Storyboard.TargetName="wb" Storyboard.TargetProperty="Opacity" From="0.2" To="1" Duration="0:0:6"/> </Storyboard> <Storyboard x:Key="end"> <DoubleAnimation Storyboard.TargetName="wb" Storyboard.TargetProperty="Opacity" Duration="0:0:5" From="1" To="0"/> <DoubleAnimation Storyboard.TargetName="rt" Storyboard.TargetProperty="Angle" Duration="0:0:5" From="0" To="720"/> <DoubleAnimation Storyboard.TargetName="sct" Storyboard.TargetProperty="ScaleX" Duration="0:0:5" From="1" To="0.3"/> <DoubleAnimation Storyboard.TargetName="sct" Storyboard.TargetProperty="ScaleY" Duration="0:0:5" From="1" To="0.1"/> </Storyboard> </Window.Resources> </Window>
在X按鈕點擊時,我們不是直接Close窗口,因為我們還要關閉動畫,所以,單擊X按鈕時播放關閉動畫,當動畫結束時,才把窗口真正關掉。
- public partial class MainWindow : Window
- {
- Storyboard stdStart, stdEnd;
- public MainWindow()
- {
- InitializeComponent();
- stdStart = (Storyboard)this.Resources["start"];
- stdEnd = (Storyboard)this.Resources["end"];
- stdStart.Completed += (a, b) =>
- {
- this.root.Clip = null;
- };
- stdEnd.Completed += (c, d) =>
- {
- this.Close();
- };
- this.Loaded += MainWindow_Loaded;
- }
- void MainWindow_Loaded(object sender, RoutedEventArgs e)
- {
- stdStart.Begin();
- }
- private void onClick(object sender, RoutedEventArgs e)
- {
- stdEnd.Begin();
- }
- private void onLDown(object sender, MouseButtonEventArgs e)
- {
- this.DragMove();
- e.Handled = true;
- }
- private void onMin(object sender, RoutedEventArgs e)
- {
- this.WindowState = System.Windows.WindowState.Minimized;
- }
- }
public partial class MainWindow : Window { Storyboard stdStart, stdEnd; public MainWindow() { InitializeComponent(); stdStart = (Storyboard)this.Resources["start"]; stdEnd = (Storyboard)this.Resources["end"]; stdStart.Completed += (a, b) => { this.root.Clip = null; }; stdEnd.Completed += (c, d) => { this.Close(); }; this.Loaded += MainWindow_Loaded; } void MainWindow_Loaded(object sender, RoutedEventArgs e) { stdStart.Begin(); } private void onClick(object sender, RoutedEventArgs e) { stdEnd.Begin(); } private void onLDown(object sender, MouseButtonEventArgs e) { this.DragMove(); e.Handled = true; } private void onMin(object sender, RoutedEventArgs e) { this.WindowState = System.Windows.WindowState.Minimized; } }
好的,現在來看看這個窗口動畫吧。
下圖是窗口啟動時的動畫。
下圖是窗體關閉時的動畫。窗體一邊旋轉,一邊縮小,一邊淡出,直到消失。
源代碼我隨后上傳到資源區。