读书人

WPF制造窗口的启动和关闭动画

发布时间: 2013-01-07 10:02:25 作者: rapoo

WPF制作窗口的启动和关闭动画

以下是用WPF实现的的一个窗口,为了使演示变得简单,我在窗口中只放了一个按钮。如下图所示:

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>

那么,通过这四个矩形的裁剪,窗口会变成什么模样呢。看下图。

WPF制造窗口的启动和关闭动画

下面就是窗口的启动动画,通过对这四个矩形进行动画处理,在窗体的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;        }    }


好的,现在来看看这个窗口动画吧。

下图是窗口启动时的动画。

WPF制造窗口的启动和关闭动画

下图是窗体关闭时的动画。窗体一边旋转,一边缩小,一边淡出,直到消失。

WPF制造窗口的启动和关闭动画

源代码我随后上传到资源区。

读书人网 >编程

热点推荐