1、动态变换。
变换提供了自定义元素的最强大方式之一。每个元素都能以两种不同的方式使用变换,RenderTransform属性和LayoutTransform属性。RenderTransform属性效率更高。因为是在布局之后应用变换,并且用于变换最终的渲染输出。LayoutTransform在布局前应用,从而其他控件需要重新排列以适应变换。
使用 RenderTransform:
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="100"></Setter>
<Setter Property="Height" Value="60"></Setter>
<Setter Property="Margin" Value="10"></Setter>
<Setter Property="FontSize" Value="20"></Setter>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"></Setter>
<Setter Property="RenderTransform">
<Setter.Value>
<!--使用RotateTransform时,一定要使用TransformGroup,否则不能进行动画哦-->
<TransformGroup>
<RotateTransform></RotateTransform>
</TransformGroup>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever" Storyboard.TargetProperty="RenderTransform.Children[0].Angle">
<DoubleAnimation From="0" To="360" Duration="0:0:2"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="RenderTransform.Children[0].Angle">
<DoubleAnimation To="0" Duration="0:0:1"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<Button Content="Test1"></Button>
<Button Content="Tes2"></Button>
<Button Content="Test3"></Button>
<Button Content="Test4"></Button>
</StackPanel>
效果图:
使用LayOutTransform:
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="100"></Setter>
<Setter Property="Height" Value="60"></Setter>
<Setter Property="Margin" Value="10"></Setter>
<Setter Property="FontSize" Value="20"></Setter>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"></Setter>
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform></RotateTransform>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever" Storyboard.TargetProperty="LayoutTransform.Angle">
<DoubleAnimation From="0" To="360" Duration="0:0:2"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="LayoutTransform.Angle">
<DoubleAnimation To="0" Duration="0:0:1"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<Button Content="Test1"></Button>
<Button Content="Tes2"></Button>
<Button Content="Test3"></Button>
<Button Content="Test4"></Button>
</StackPanel>
效果图:
2、动态改变多个变换。
就是在TransformGroup中放置多个变换类。
xaml代码:
<Window.Triggers> <EventTrigger RoutedEvent="Window.Loaded"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard SpeedRatio="1.5"> <DoubleAnimation Storyboard.TargetName="border_element" Storyboard.TargetProperty="Opacity" From="0.2" To="1" Duration="0:0:1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="border_element" Storyboard.TargetProperty="RenderTransform.Children[1].Angle" From="50" To="0" Duration="0:0:2" ></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="border_element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleX" From="0" To="1" Duration="0:0:2" AccelerationRatio="1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="border_element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleY" From="0" To="1" Duration="0:0:2" AccelerationRatio="1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="border_element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleX" To="0.98" BeginTime="0:0:2" Duration="0:0:0.05" DecelerationRatio="1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="border_element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleY" To="0.98" BeginTime="0:0:2" Duration="0:0:0.05" DecelerationRatio="1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="border_element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleX" To="1" BeginTime="0:0:2.05" Duration="0:0:0.2" AccelerationRatio="1"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="border_element" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleY" To="1" BeginTime="0:0:2.05" Duration="0:0:0.2" AccelerationRatio="1"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Window.Triggers> <Grid> <Border Name="border_element" BorderBrush="Red" BorderThickness="3" CornerRadius="5"> <Border.RenderTransform> <TransformGroup> <ScaleTransform></ScaleTransform> <RotateTransform></RotateTransform> </TransformGroup> </Border.RenderTransform> <ListBox FontSize="20"> <ListBoxItem Content="A"></ListBoxItem> <ListBoxItem Content="B"></ListBoxItem> <ListBoxItem Content="C"></ListBoxItem> <ListBoxItem Content="D"></ListBoxItem> <ListBoxItem Content="E"></ListBoxItem> <ListBoxItem Content="F"></ListBoxItem> <ListBoxItem Content="G"></ListBoxItem> <ListBoxItem Content="H"></ListBoxItem> <ListBoxItem Content="I"></ListBoxItem> <ListBoxItem Content="J"></ListBoxItem> <ListBoxItem Content="K"></ListBoxItem> <ListBoxItem Content="L"></ListBoxItem> <ListBoxItem Content="M"></ListBoxItem> <ListBoxItem Content="N"></ListBoxItem> <ListBoxItem Content="O"></ListBoxItem> <ListBoxItem Content="P"></ListBoxItem> <ListBoxItem Content="Q"></ListBoxItem> <ListBoxItem Content="R"></ListBoxItem> <ListBoxItem Content="S"></ListBoxItem> <ListBoxItem Content="T"></ListBoxItem> <ListBoxItem Content="U"></ListBoxItem> <ListBoxItem Content="V"></ListBoxItem> <ListBoxItem Content="W"></ListBoxItem> <ListBoxItem Content="X"></ListBoxItem> <ListBoxItem Content="Y"></ListBoxItem> <ListBoxItem Content="Z"></ListBoxItem> </ListBox> </Border> </Grid>
效果图:
3、动态改变画刷。
使用ColorAnimation改变颜色,使用PointAnimatin改变坐标。
xaml代码:
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<!--设置Fill.GradientOrigin属性。-->
<PointAnimation Storyboard.TargetName="ellipse1"
Storyboard.TargetProperty="Fill.GradientOrigin"
To="1,1" Duration="0:0:5" ></PointAnimation>
<!--设置Fill.GradientStops属性。-->
<ColorAnimation Storyboard.TargetName="ellipse1"
Storyboard.TargetProperty="Fill.GradientStops[0].Color"
To="Pink" Duration="0:0:5" ></ColorAnimation>
<ColorAnimation Storyboard.TargetName="ellipse1"
Storyboard.TargetProperty="Fill.GradientStops[1].Color"
To="Gold" Duration="0:0:5" ></ColorAnimation>
<ColorAnimation Storyboard.TargetName="ellipse1"
Storyboard.TargetProperty="Fill.GradientStops[2].Color"
To="Gray" Duration="0:0:5" ></ColorAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Grid>
<Ellipse Name="ellipse1" Width="150" Height="150">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.1,0.1">
<RadialGradientBrush.GradientStops>
<GradientStop Offset="0.3" Color="Red"></GradientStop>
<GradientStop Offset="0.6" Color="Green"></GradientStop>
<GradientStop Offset="0.9" Color="Yellow"></GradientStop>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
效果图:
4、动态改变像素着色器。
<Window.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="btn1" Storyboard.TargetProperty="Effect.Radius">
<DoubleAnimation To="10" Duration="0:0:2" ></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="btn1" Storyboard.TargetProperty="Effect.Radius">
<DoubleAnimation To="0" Duration="0:0:1" ></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<StackPanel>
<Button Name="btn1" Width="200" Height="80" Content="Hello,World!!!" FontSize="20">
<Button.Effect>
<BlurEffect Radius="0"></BlurEffect>
</Button.Effect>
</Button>
</StackPanel>
效果图:
5、关键帧动画。
如果需要创建具有多个分段的动画和不规则移动的动画,这个时候可以使用关键帧动画。关键帧动画是由许多较短的段构成的动画,每段表示动画的初始值、最终值或中间值。当运行动画时,她平滑地从一个值移动到另一个值。关键帧对象基本上都有Value属性和KeyTime属性。和其他普通动画不同的是Value属性的数据类型,在LinearPointKeyFrame类中是Point类型,在DoubleKeyFrame类中是double类型。
xaml代码:
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="Fill.GradientOrigin">
<!--PointAnimationUsingKeyFrames:使用线性插值-->
<PointAnimationUsingKeyFrames>
<!--LinearPointKeyFrame:关键帧对象-->
<LinearPointKeyFrame Value="0.7,0.3" KeyTime="0:0:0"></LinearPointKeyFrame>
<LinearPointKeyFrame Value="0.3,0.7" KeyTime="0:0:3"></LinearPointKeyFrame>
<LinearPointKeyFrame Value="0.5,0.2" KeyTime="0:0:5"></LinearPointKeyFrame>
</PointAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Grid>
<Ellipse Width="200" Height="200" Name="ellipse1">
<Ellipse.Fill>
<RadialGradientBrush>
<RadialGradientBrush.GradientStops>
<GradientStop Offset="0.3" Color="Red"></GradientStop>
<GradientStop Offset="0.6" Color="Yellow"></GradientStop>
<GradientStop Offset="0.9" Color="Green"></GradientStop>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
效果图:
6、离散的关键帧动画。
如上图,使用的是线性关键帧动画,所以,它在关键帧动画之间平滑地过度。另一种选择是使用离散关键帧,离散关键帧不是进行插值,当到达关键时间时,属性突然改变为新值。线性关键帧类通常使用"Linear"+数据类型+KeyFrame"的形式进行命名,离散关键帧类使用"Discrete数据类型+KeyFrame"的形式命名。当运行这个动画时中心点会在适当的时间从一个位置跳转到下一个位置。所有关键帧动画类都支持离散关键帧,但只有一部分关键动画类支持线性关键帧。
Xaml代码:
<Window.Triggers>
<EventTrigger RoutedEvent="Button.Click" SourceName="btn1">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="Fill.GradientOrigin">
<PointAnimationUsingKeyFrames>
<DiscretePointKeyFrame Value="0.2,0.8" KeyTime="0:0:1"></DiscretePointKeyFrame>
<DiscretePointKeyFrame Value="0.7,0.8" KeyTime="0:0:2"></DiscretePointKeyFrame>
<DiscretePointKeyFrame Value="0.3,0.2" KeyTime="0:0:3"></DiscretePointKeyFrame>
</PointAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="3*"></RowDefinition>
</Grid.RowDefinitions>
<Button Name="btn1" Content="点击进行关键帧动画" Width="150" Margin="10" Grid.Row="0"></Button>
<Ellipse Name="ellipse1" Grid.Row="1" Width="180" Height="180">
<Ellipse.Fill >
<RadialGradientBrush>
<RadialGradientBrush.GradientStops>
<GradientStop Offset="0.2" Color="Red"></GradientStop>
<GradientStop Offset="0.4" Color="Yellow"></GradientStop>
<GradientStop Offset="0.6" Color="Gray"></GradientStop>
<GradientStop Offset="0.8" Color="Khaki"></GradientStop>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
效果图:
7、缓动关键帧。
由离散关键帧可以得出:尽管关键帧动画被分割成多段,但每段仍使用普通的线性插值。常用的缓动关键帧类有:EasingDoubleKeyFrame、EasingColorKeyFrame、EasyingPointKeyFrame。每个缓动关键帧类和对应的线性插值关键帧类的工作方式相同,但是额外提供了EasyingFunction属性。
Xaml代码:
<Window.Triggers>
<EventTrigger RoutedEvent="Button.Click" SourceName="btn1">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="Fill.GradientOrigin">
<PointAnimationUsingKeyFrames>
<LinearPointKeyFrame Value="0.7,0.3" KeyTime="0:0:5"></LinearPointKeyFrame>
<!--使用缓动函数类-->
<EasingPointKeyFrame Value="0.3,0.7" KeyTime="0:0:5">
<EasingPointKeyFrame.EasingFunction>
<CircleEase></CircleEase>
</EasingPointKeyFrame.EasingFunction>
</EasingPointKeyFrame>
<LinearPointKeyFrame Value="0.5,0.9" KeyTime="0:0:8"></LinearPointKeyFrame>
<LinearPointKeyFrame Value="0.9,0.6" KeyTime="0:0:10"></LinearPointKeyFrame>
<LinearPointKeyFrame Value="0.8,0.2" KeyTime="0:0:12"></LinearPointKeyFrame>
<LinearPointKeyFrame Value="0.7,0.3" KeyTime="0:0:14"></LinearPointKeyFrame>
</PointAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="3*"></RowDefinition>
</Grid.RowDefinitions>
<Button Name="btn1" Content="点击进行关键帧动画" Width="150" Margin="10" Grid.Row="0"></Button>
<Ellipse Name="ellipse1" Grid.Row="1" Width="180" Height="180">
<Ellipse.Fill >
<RadialGradientBrush>
<RadialGradientBrush.GradientStops>
<GradientStop Offset="0.2" Color="Red"></GradientStop>
<GradientStop Offset="0.4" Color="Yellow"></GradientStop>
<GradientStop Offset="0.6" Color="Gray"></GradientStop>
<GradientStop Offset="0.8" Color="Khaki"></GradientStop>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
效果图:
8、关键帧动画。
<Window.Resources>
<PathGeometry x:Key="path">
<PathFigure IsClosed="True">
<ArcSegment Point="100,200" Size="15,10" SweepDirection="Clockwise"></ArcSegment>
<ArcSegment Point="400,50" Size="5,5"></ArcSegment>
</PathFigure>
</PathGeometry>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingPath Storyboard.TargetName="image"
Storyboard.TargetProperty="(Canvas.Left)"
PathGeometry="{StaticResource path}"
Duration="0:0:5" RepeatBehavior="Forever" Source="X">
</DoubleAnimationUsingPath>
<DoubleAnimationUsingPath Storyboard.TargetName="image"
Storyboard.TargetProperty="(Canvas.Top)"
PathGeometry="{StaticResource path}"
Duration="0:0:5" RepeatBehavior="Forever" Source="Y">
</DoubleAnimationUsingPath>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Canvas>
<Path Stroke="Red" StrokeThickness="1" Data="{StaticResource path}" Canvas.Top="10" Canvas.Left="10"></Path>
<!--<Ellipse Name="image" Width="15" Height="15" Fill="Green"></Ellipse>-->
<Image Name="image">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing Brush="LightSkyBlue">
<GeometryDrawing.Geometry>
<GeometryGroup>
<EllipseGeometry Center="10,10" RadiusX="9" RadiusY="4"></EllipseGeometry>
<EllipseGeometry Center="10,10" RadiusX="4" RadiusY="9"></EllipseGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Black"></Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Canvas>
效果图:
9、基于帧的动画。
使用帧的动画要为静态的CompositionTarger.Rendering事件关联事件处理程序,一旦关联这个处理程序,WPF就开始不断地调用这个事件处理程序,WPF将每秒调用60次。当动画结束后,分离事件处理程序。
xaml代码:
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="3*"></RowDefinition>
</Grid.RowDefinitions>
<Button Width="100" Name="btnStart" Content="开始" FontSize="20" HorizontalAlignment="Left" Click="btnStart_Click"></Button>
<Button Width="100" Name="btnStop" Content="停止" FontSize="20" HorizontalAlignment="Right" Click="btnStop_Click"></Button>
<Canvas Name="canvas" Grid.Row="1">
</Canvas>
</Grid>
后台代码(EllipseInfo类):
public class EllipseInfo
{
public Ellipse Ellipse { get; set; }
/// <summary>
/// Y轴的速度。
/// </summary>
public double VelocityY { get; set; }
public EllipseInfo(Ellipse _ellipse, double _velocityY)
{
Ellipse = _ellipse;
VelocityY = _velocityY;
}
}
后台代码:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private List<EllipseInfo> listEllipse = new List<EllipseInfo>(); //声明一个Ellipse类型的list集合。 private double acclerationY = 0.1;//Y轴加速度。 private int minStartingSpeed = 1; //开始时最慢的速度。 private int maxStartingSpeed = 50; //开始时最快速度。 private double speedRatio = 0.1; //速度比率:0.1 private int minEllipses = 20; //最少椭圆数量。 private int maxEllipses = 100; //最多椭圆数量。 private int ellipseRadius = 10; //椭圆的半径。 private bool rendering = false; private void btnStart_Click(object sender, RoutedEventArgs e) { if (rendering == false) { listEllipse.Clear(); canvas.Children.Clear(); CompositionTarget.Rendering += CompositionTarget_Rendering; rendering = true; } } void CompositionTarget_Rendering(object sender, EventArgs e) { if (listEllipse.Count == 0) { int halfCanvasWidth = (int)canvas.ActualWidth / 2; Random random = new Random(); int ellipseCount = random.Next(minEllipses, maxEllipses + 1); for (int i = 0; i < ellipseCount; i++) { Ellipse ellipse = new Ellipse();//创建一个椭圆。 ellipse.Fill = new SolidColorBrush(Colors.LimeGreen);//设置椭圆颜色。 ellipse.Width = ellipseRadius;//设置椭圆的宽。 ellipse.Height = ellipseRadius;//设置椭圆的高。 Canvas.SetLeft(ellipse, halfCanvasWidth + random.Next(-halfCanvasWidth, halfCanvasWidth)); //设置椭圆位置。 Canvas.SetTop(ellipse, 0); //设置椭圆位置。 canvas.Children.Add(ellipse); //将创建出来的椭圆加入到canvas面板中。 EllipseInfo info = new EllipseInfo(ellipse, speedRatio * random.Next(minStartingSpeed, maxStartingSpeed)); //实例化EllipseInfo。 listEllipse.Add(info); //将创建好的EllipseInfo加入到listEllipse集合中。 } } else { for (int i = listEllipse.Count-1; i >= 0; i--) { EllipseInfo info = listEllipse[i]; //得到椭圆。 double top = Canvas.GetTop(info.Ellipse);//得到top坐标值。 Canvas.SetTop(info.Ellipse, top + 1 * info.VelocityY); if (top >= canvas.ActualHeight - ellipseRadius * 2 - 10) { listEllipse.Remove(info); } else { info.VelocityY += acclerationY; } if (listEllipse.Count == 0) { StopRendering(); } } } } //取消关联事件处理程序。 private void StopRendering() { CompositionTarget.Rendering -= CompositionTarget_Rendering; rendering = false; } private void btnStop_Click(object sender, RoutedEventArgs e) { StopRendering(); } }
效果图:
End!