WPF如何仿制QQ2013登录窗口的关闭效果

昨天,有位朋友问我,WPF能做出像QQ2013窗口在关闭时那个貌似透明过渡的动画吗?我就歪着脸跟他说:"只有你想不到的,没有WPF做不到的"。

他又接着说:"我知道肯定会用到动画来控制画刷,但是那个透明的'淡出'怎么弄呢?"

我就给他演示了一个类似的效果。

大家有没有注意到System.Windows.UIElement.OpacityMask这个属性,它是一个Brush类型,也就是说,你可以使用任意Brush的类来充当。这个属性只提取赋给它的Brush中的所有颜色的A值。即ARGB中的A值,其他通道将忽略,然后用这些不透明值来替目标可视化元素中的不透明值。具体大家可参考MSDN。

其实原理非常简单,就以下两个条件:一是把窗口变成透明,这个不介绍,大家可以看我后面贴的代码。第二就是OpacityMask属性用渐变画刷,只有这样才能做到渐变透明的效果。然后我们就对这个渐变画刷中各颜色点的Offset进行动画处理就可以了。

先看看最终效果,看看像不像,呵呵。

原理很easy,我就放XAML了。

 1 <Window x:Class="WpfApplication1.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         Title="MainWindow" Height="300" Width="300"
 5         AllowsTransparency="True" Background="Transparent" WindowStyle="None"
 6         WindowStartupLocation="CenterScreen">
 7     <Grid x:Name="layoutroot">
 8         <Grid.OpacityMask>
 9             <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
10                 <GradientStop Color="#FF000000" Offset="0"/>
11                 <GradientStop Color="#FF000000" Offset="1"/>
12                 <GradientStop Color="#FF000000" Offset="1"/>
13             </LinearGradientBrush>
14         </Grid.OpacityMask>
15         <Grid.Clip>
16             <EllipseGeometry Center="150 150" RadiusX="150" RadiusY="150"/>
17         </Grid.Clip>
18         <Grid.Background>
19             <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
20                 <GradientStop Color="#FF4141A6" Offset="0.003"/>
21                 <GradientStop Color="#FF5E5ED4" Offset="1"/>
22                 <GradientStop Color="#FFDCDCFD" Offset="0.38"/>
23                 <GradientStop Color="#FF161674" Offset="0.84"/>
24             </LinearGradientBrush>
25         </Grid.Background>
26         <Button Content="关闭" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="20" Background="#FFF70D0D" Foreground="White" BorderBrush="#FFD8A00A" FontSize="28" Click="OnClick">
27             <Button.Template>
28                 <ControlTemplate TargetType="{x:Type Button}">
29                     <Grid>
30                         <Ellipse x:Name="bg" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="2" />
31                         <Ellipse x:Name="fr" Opacity="0" >
32                             <Ellipse.Fill>
33                                 <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
34                                     <GradientStop Color="#CCFFFFFF" Offset="0"/>
35                                     <GradientStop Offset="1"/>
36                                     <GradientStop Color="#7FFFFFFF" Offset="0.392"/>
37                                 </LinearGradientBrush>
38                             </Ellipse.Fill>
39                         </Ellipse>
40                         <ContentPresenter x:Name="ContentPresenter" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
41                     </Grid>
42                     <ControlTemplate.Triggers>
43                         <Trigger Property="UIElement.IsMouseOver" Value="True" >
44                             <Setter TargetName="fr" Property="Opacity" Value="1"/>
45                         </Trigger>
46                     </ControlTemplate.Triggers>
47                 </ControlTemplate>
48             </Button.Template>
49         </Button>
50         <Grid.Resources>
51             <Storyboard x:Key="std">
52                 <DoubleAnimation From="1" To="0" Duration="0:0:6"
53                                  Storyboard.TargetName="layoutroot"
54                                  Storyboard.TargetProperty="(UIElement.OpacityMask).(GradientBrush.GradientStops)[1].Offset"/>
55                 <DoubleAnimation Duration="0:0:4.5" BeginTime="0:0:1.5" From="1" To="0"
56                                  Storyboard.TargetName="layoutroot"
57                                  Storyboard.TargetProperty="(UIElement.OpacityMask).(GradientBrush.GradientStops)[2].Offset"/>
58                 <ColorAnimation Duration="0" To="#00000000" Storyboard.TargetName="layoutroot"
59                                  Storyboard.TargetProperty="(UIElement.OpacityMask).(GradientBrush.GradientStops)[2].Color"/>
60             </Storyboard>
61         </Grid.Resources>
62     </Grid>
63 </Window>

 

然后是少量的处理代码。

 1     public partial class MainWindow : Window
 2     {
 3         System.Windows.Media.Animation.Storyboard std = null;
 4         public MainWindow()
 5         {
 6             InitializeComponent();
 7             std = (System.Windows.Media.Animation.Storyboard)layoutroot.Resources["std"];
 8             std.Completed += (t, r) => this.Close();
 9             this.layoutroot.Loaded += (sd, ee) => {
10                 // 设置Grid的圆形剪辑的圆心和半径
11                 EllipseGeometry eg = (EllipseGeometry)this.layoutroot.Clip;
12                 double dx = layoutroot.ActualWidth /2d;
13                 double dy=layoutroot.ActualHeight/2d;
14                 eg.Center = new Point(dx, dy);
15                 eg.RadiusX = dx;
16                 eg.RadiusY = dy;
17             };
18 
19         }
20 
21 
22         private void OnClick(object sender, RoutedEventArgs e)
23         {
24             if (std != null)
25             {
26                 std.Begin();
27             }
28         }
29     }

OK,完事,88。

posted @ 2013-11-30 11:54  东邪独孤  阅读(4207)  评论(10编辑  收藏  举报