以下是用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進行剪裁,即設定它的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>
那麼,通過這四個矩形的裁剪,視窗會變成什麼模樣呢。看。
下面就是視窗的啟動動畫,通過對這四個矩形進行動畫處理,在表單的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>
上面的資源中,包含兩個動畫,後面一個是視窗關閉時的動畫。
另外,我們的視窗還需要兩個小按鈕,就是標題列上方的“最小化”和“關閉”按鈕,用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>
由於這些小按鈕都比較相似,因此,我們先定義一個通用的樣式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>
在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; } }
好的,現在來看看這個視窗動畫吧。
是視窗啟動時的動畫。
是表單關閉時的動畫。表單一邊旋轉,一邊縮小,一邊淡出,直到消失。
原始碼我隨後上傳到資源區。