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。