WPF 利用路径动画做一个环形加载动画
2020年10月24日 增加缓动函数方式
我们保持代码不变,直接使用缓动函数,缓动函数内置很多运动方式
关于函数运动方式可以参考之前给出的网址。或者自己试试,直接使用某个函数即可。
<Window.Triggers> <EventTrigger RoutedEvent="Button.Click" SourceName="c1"> <BeginStoryboard> <Storyboard> <DoubleAnimationUsingKeyFrames BeginTime="0:0:0.1" RepeatBehavior="Forever" Storyboard.TargetProperty="Angle" Storyboard.TargetName="rt1" > <EasingDoubleKeyFrame KeyTime="0" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:2" Value="360"> <EasingDoubleKeyFrame.EasingFunction> <ExponentialEase EasingMode="EaseInOut"/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="0:0:0.2" RepeatBehavior="Forever" Storyboard.TargetProperty="Angle" Storyboard.TargetName="rt2" > <EasingDoubleKeyFrame Value="0" KeyTime="0:0:0" /> <EasingDoubleKeyFrame KeyTime="0:0:2" Value="360"> <EasingDoubleKeyFrame.EasingFunction> <ExponentialEase EasingMode="EaseInOut"/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="0:0:0.3" RepeatBehavior="Forever" Storyboard.TargetProperty="Angle" Storyboard.TargetName="rt3" > <EasingDoubleKeyFrame Value="0" KeyTime="0:0:0" /> <EasingDoubleKeyFrame KeyTime="0:0:2" Value="360"> <EasingDoubleKeyFrame.EasingFunction> <ExponentialEase EasingMode="EaseInOut"/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="0:0:0.4 " RepeatBehavior="Forever" Storyboard.TargetProperty="Angle" Storyboard.TargetName="rt4" > <EasingDoubleKeyFrame Value="0" KeyTime="0:0:0" /> <EasingDoubleKeyFrame KeyTime="0:0:2" Value="360"> <EasingDoubleKeyFrame.EasingFunction> <ExponentialEase EasingMode="EaseInOut"/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="0:0:0.5" RepeatBehavior="Forever" Storyboard.TargetProperty="Angle" Storyboard.TargetName="rt5" > <EasingDoubleKeyFrame Value="0" KeyTime="0:0:0" /> <EasingDoubleKeyFrame KeyTime="0:0:2" Value="360"> <EasingDoubleKeyFrame.EasingFunction> <ExponentialEase EasingMode="EaseInOut"/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Window.Triggers> <Grid > <Button x:Name="c1" Height="40" Width="50" VerticalAlignment="Bottom"/> <ContentControl Height="150" Width="150" RenderTransformOrigin="0.5 ,0.5"> <ContentControl.RenderTransform> <RotateTransform x:Name="rt1"/> </ContentControl.RenderTransform> <Ellipse Width="15" Height="15" Fill="Red" VerticalAlignment="Bottom"/> </ContentControl> <ContentControl Height="150" Width="150" RenderTransformOrigin="0.5 ,0.5"> <ContentControl.RenderTransform> <RotateTransform x:Name="rt2"/> </ContentControl.RenderTransform> <Ellipse Width="15" Height="15" Fill="Red" VerticalAlignment="Bottom"/> </ContentControl> <ContentControl Height="150" Width="150" RenderTransformOrigin="0.5 ,0.5"> <ContentControl.RenderTransform> <RotateTransform x:Name="rt3"/> </ContentControl.RenderTransform> <Ellipse Width="15" Height="15" Fill="Red" VerticalAlignment="Bottom"/> </ContentControl> <ContentControl Height="150" Width="150" RenderTransformOrigin="0.5 ,0.5"> <ContentControl.RenderTransform> <RotateTransform x:Name="rt4"/> </ContentControl.RenderTransform> <Ellipse Width="15" Height="15" Fill="Red" VerticalAlignment="Bottom"/> </ContentControl> <ContentControl Height="150" Width="150" RenderTransformOrigin="0.5 ,0.5"> <ContentControl.RenderTransform> <RotateTransform x:Name="rt5"/> </ContentControl.RenderTransform> <Ellipse Width="15" Height="15" Fill="Red" VerticalAlignment="Bottom"/> </ContentControl> </Grid>
截图
*************************************************************************************************************************************************
2020年10月22日 增加其他方法【样条动画】
在之前的的文章中用动画速率来实现球的运行速度达到缓速的效果。
其实,WPF原生中自带有此类的东西,通过某个曲线来模拟速度的快慢:MSDN网址
本文的球动画,差不多直接使用一个三次方贝塞尔曲线差不多就能模拟。
但不能使用路径动画了,我们需要改变新的动画方式。
首先确定关键词BeginTime,KeyTime,Value,Duration:
在动画中时间线中当时间为KeyTime时动画所应用的值应该为KeyValue,
如果一个时间线内有多个运行对象,则每个对象BeginTime为当前时间线运行的时间某个时刻,并且当时间线的时刻符合BeginTime时启动动画。
此时每个对象的KeyValue是当前对象自开始运行时计算独立的运行时间,当对象的运行时间符合KeyTime时所应用到对象的属性的值
Duration则是规定的总运行时间长,也可以不用写,默认为所有对象运行时长的和。
至于为什么用贝塞尔曲线模拟运行速度,
首先在WPF动画中规定,贝塞尔的起点为(0,0),终点(1,1)其次贝塞尔是一个光滑的曲线,所以我们只用去控制第一个控制点和第二个控制点制造曲线就会产生光滑的曲线,
输入两个控制点和两个默认点的后通过公式计算即可得到0~1的每一个时刻的值与终点(1,1)的比值,即为速度。当然也可以直接使用blend去拖动图表的控制点快速得到想要的效果。
【blend贝塞尔曲线绘制工具】
但是我认为适当了解原理还是比较好的。
动画是一个细心的活,慢慢调
下面是代码
<Window.Triggers> <EventTrigger RoutedEvent="Button.Click" SourceName="c1"> <BeginStoryboard> <Storyboard> <DoubleAnimationUsingKeyFrames BeginTime="0:0:0" RepeatBehavior="Forever" Storyboard.TargetProperty="Angle" Storyboard.TargetName="rt1" > <SplineDoubleKeyFrame Value="0" KeyTime="0:0:0" /> <SplineDoubleKeyFrame Value="360" KeyTime="0:0:2" KeySpline="0.13,1,0.9,0.8"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="0:0:0.2" RepeatBehavior="Forever" Storyboard.TargetProperty="Angle" Storyboard.TargetName="rt2" > <SplineDoubleKeyFrame Value="0" KeyTime="0:0:0" /> <SplineDoubleKeyFrame Value="360" KeyTime="0:0:2" KeySpline="0.13,1,0.9,0.8"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="0:0:0.3" RepeatBehavior="Forever" Storyboard.TargetProperty="Angle" Storyboard.TargetName="rt3" > <SplineDoubleKeyFrame Value="0" KeyTime="0:0:0" /> <SplineDoubleKeyFrame Value="360" KeyTime="0:0:2" KeySpline="0.13,1,0.9,0.8"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="0:0:0.4 " RepeatBehavior="Forever" Storyboard.TargetProperty="Angle" Storyboard.TargetName="rt4" > <SplineDoubleKeyFrame Value="0" KeyTime="0:0:0" /> <SplineDoubleKeyFrame Value="360" KeyTime="0:0:2" KeySpline="0.13,1,0.9,0.8"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="0:0:0.5" RepeatBehavior="Forever" Storyboard.TargetProperty="Angle" Storyboard.TargetName="rt5" > <SplineDoubleKeyFrame Value="0" KeyTime="0:0:0" /> <SplineDoubleKeyFrame Value="360" KeyTime="0:0:2" KeySpline="0.13,1,0.9,0.8"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Window.Triggers> <Grid > <Button x:Name="c1" Height="40" Width="50" VerticalAlignment="Bottom"/> <ContentControl Height="150" Width="150" RenderTransformOrigin="0.5 ,0.5"> <ContentControl.RenderTransform> <RotateTransform x:Name="rt1"/> </ContentControl.RenderTransform> <Ellipse Width="15" Height="15" Fill="Red" VerticalAlignment="Bottom"/> </ContentControl> <ContentControl Height="150" Width="150" RenderTransformOrigin="0.5 ,0.5"> <ContentControl.RenderTransform> <RotateTransform x:Name="rt2"/> </ContentControl.RenderTransform> <Ellipse Width="15" Height="15" Fill="Red" VerticalAlignment="Bottom"/> </ContentControl> <ContentControl Height="150" Width="150" RenderTransformOrigin="0.5 ,0.5"> <ContentControl.RenderTransform> <RotateTransform x:Name="rt3"/> </ContentControl.RenderTransform> <Ellipse Width="15" Height="15" Fill="Red" VerticalAlignment="Bottom"/> </ContentControl> <ContentControl Height="150" Width="150" RenderTransformOrigin="0.5 ,0.5"> <ContentControl.RenderTransform> <RotateTransform x:Name="rt4"/> </ContentControl.RenderTransform> <Ellipse Width="15" Height="15" Fill="Red" VerticalAlignment="Bottom"/> </ContentControl> <ContentControl Height="150" Width="150" RenderTransformOrigin="0.5 ,0.5"> <ContentControl.RenderTransform> <RotateTransform x:Name="rt5"/> </ContentControl.RenderTransform> <Ellipse Width="15" Height="15" Fill="Red" VerticalAlignment="Bottom"/> </ContentControl> </Grid>
截图
***************************************************************************************************************************************************************************************************************
简单用一个路径动画做一个环形加载动画
四个点,启动时间各个不同,运行时间相同。启动时圆形半径为0,启动后恢复正常半径。
gif截图略慢,实际运行还是可以的
<Window.Resources> <PathGeometry x:Key="EllipesPath" Figures="M 5 10 a 35 35 0 1 1 1 1 Z"/> </Window.Resources> <Grid> <Canvas x:Name="cs"> <Path Panel.ZIndex="1" x:Name="Geo" Visibility="Visible" Canvas.Top="100" Canvas.Left="100" Fill="Red" Stroke="Red" > <Path.Data> <GeometryGroup x:Name="G1" FillRule="Nonzero" > <EllipseGeometry x:Name="eg1" Center="05 10" RadiusX="0" RadiusY="0" /> <EllipseGeometry x:Name="eg2" Center="25 10" RadiusX="0" RadiusY="0"/> <EllipseGeometry x:Name="eg3" Center="45 10" RadiusX="0" RadiusY="0"/> <EllipseGeometry x:Name="eg4" Center="65 10" RadiusX="0" RadiusY="0"/> </GeometryGroup> </Path.Data> <Path.RenderTransform> <RotateTransform/> </Path.RenderTransform> <Path.Triggers> <EventTrigger RoutedEvent="Path.Loaded" > <BeginStoryboard x:Name="P1" > <Storyboard> <DoubleAnimation Storyboard.TargetName="eg1" Storyboard.TargetProperty="RadiusX" To="5" BeginTime="0:0:0" /> <DoubleAnimation Storyboard.TargetName="eg1" Storyboard.TargetProperty="RadiusY" To="5" BeginTime="0:0:0" /> <PointAnimationUsingPath Storyboard.TargetName="eg1" Storyboard.TargetProperty="Center" RepeatBehavior="Forever" PathGeometry="{DynamicResource EllipesPath}" Duration="0:0:4" BeginTime="0:0:0.1" AccelerationRatio="0.7" SpeedRatio="1.2"/> </Storyboard> </BeginStoryboard> <BeginStoryboard x:Name="P2"> <Storyboard> <DoubleAnimation Storyboard.TargetName="eg2" Storyboard.TargetProperty="RadiusX" To="5" BeginTime="0:0:0.5" /> <DoubleAnimation Storyboard.TargetName="eg2" Storyboard.TargetProperty="RadiusY" To="5" BeginTime="0:0:0.5" /> <PointAnimationUsingPath Storyboard.TargetName="eg2" Storyboard.TargetProperty="Center" RepeatBehavior="Forever" PathGeometry="{DynamicResource EllipesPath}" Duration="0:0:4" BeginTime="0:0:0.5" AccelerationRatio="0.7" SpeedRatio="1.2" /> </Storyboard> </BeginStoryboard> <BeginStoryboard x:Name="P3"> <Storyboard> <DoubleAnimation Storyboard.TargetName="eg3" Storyboard.TargetProperty="RadiusX" To="5" BeginTime="0:0:1" /> <DoubleAnimation Storyboard.TargetName="eg3" Storyboard.TargetProperty="RadiusY" To="5" BeginTime="0:0:1" /> <PointAnimationUsingPath RepeatBehavior="Forever" Storyboard.TargetName="eg3" Storyboard.TargetProperty="Center" PathGeometry="{DynamicResource EllipesPath}" Duration="0:0:4" BeginTime="0:0:1" AccelerationRatio="0.7" SpeedRatio="1.2"/> </Storyboard> </BeginStoryboard> <BeginStoryboard x:Name="P4"> <Storyboard> <DoubleAnimation Storyboard.TargetName="eg4" Storyboard.TargetProperty="RadiusX" To="5" BeginTime="0:0:1.5" /> <DoubleAnimation Storyboard.TargetName="eg4" Storyboard.TargetProperty="RadiusY" To="5" BeginTime="0:0:1.5" /> <PointAnimationUsingPath RepeatBehavior="Forever" Storyboard.TargetName="eg4" Storyboard.TargetProperty="Center" PathGeometry="{DynamicResource EllipesPath}" Duration="0:0:4" BeginTime="0:0:1.5" AccelerationRatio="0.7" SpeedRatio="1.2"/> </Storyboard> </BeginStoryboard> </EventTrigger> </Path.Triggers> </Path> <Path Canvas.Top="100" Canvas.Left="100" Stroke="Red" Visibility="Visible" StrokeThickness="1" Data="{DynamicResource EllipesPath}"/> </Canvas> </Grid>