最近在实现WPF的图片展开动画,一些比较基础的动画效果的实现方法在网上都能够找到,而扇形展开动画一直没有找到,不知道是个人的搜索技术不行,还是本来实现的少。
于是,只能自己动手想办法实现这种效果,所幸,最后还是让我想到了实现的方法(路径动画模拟实现)。
图片的展开动画,这里都是设置了图片控件的OpacityMask属性,然后再动画中动态修改OpacityMask属性模板里面的某个属性值以达到想要的视觉效果。
最开始的时候,想模仿“旋转展开方法”来实现扇形展开的(一条直线,以一个端点做支点,旋转直线),不过发现端点控制修改后并不是自己想要的效果,最后看了一些基于路径的动画,想着是否使用路径,其中两个端点固定,再移动另外一个端点来显示出图片,最后实验证明确实是可以的。
下面就分享一下实现代码:
1) 下面是前端用来展现动画的图片。这里因为要实现移出移入等效果,所以使用了Canvas作为父级控件。

1 <Canvas Grid.Row="1" Name="canvas1" Background="Transparent" ClipToBounds="True"> 2 <Image Name="aniCon" Source="../Images/a.jpg" Canvas.Left="40" Canvas.Top="25" Width="500"> 3 </Image> 4 </Canvas>
2)接下来是Image的OpacityMask属性代码(这里使用资源实现,当然也可以使用C#实现再赋值给Image)

1 <Style TargetType="{x:Type ContentPresenter}" x:Key="fanOutStyle"> 2 <Setter Property="UIElement.OpacityMask"> 3 <Setter.Value> 4 <DrawingBrush Stretch="None" AlignmentX="Left" AlignmentY="Top"> 5 <DrawingBrush.Drawing> 6 <GeometryDrawing Brush="LightGray"> 7 <GeometryDrawing.Geometry> 8 <GeometryGroup> 9 <PathGeometry> 10 <PathGeometry.Figures> 11 <PathFigureCollection> 12 <PathFigure IsClosed="True" StartPoint="290,182" x:Name="mFigure"> 13 <PathFigure.Segments> 14 <PathSegmentCollection> 15 <LineSegment Point="40,25" /> 16 <LineSegment Point="45,25" x:Name="aa"/> 17 </PathSegmentCollection> 18 </PathFigure.Segments> 19 </PathFigure> 20 <PathFigure IsClosed="True" StartPoint="290,182"> 21 <PathFigure.Segments> 22 <PathSegmentCollection> 23 <LineSegment Point="540,25" /> 24 <LineSegment Point="540,30"/> 25 </PathSegmentCollection> 26 </PathFigure.Segments> 27 </PathFigure> 28 <PathFigure IsClosed="True" StartPoint="290,182" > 29 <PathFigure.Segments> 30 <PathSegmentCollection> 31 <LineSegment Point="540,340" /> 32 <LineSegment Point="535,340"/> 33 </PathSegmentCollection> 34 </PathFigure.Segments> 35 </PathFigure> 36 <PathFigure IsClosed="True" StartPoint="290,182"> 37 <PathFigure.Segments> 38 <PathSegmentCollection> 39 <LineSegment Point="40,340" /> 40 <LineSegment Point="40,335"/> 41 </PathSegmentCollection> 42 </PathFigure.Segments> 43 </PathFigure> 44 </PathFigureCollection> 45 </PathGeometry.Figures> 46 </PathGeometry> 47 </GeometryGroup> 48 </GeometryDrawing.Geometry> 49 </GeometryDrawing> 50 </DrawingBrush.Drawing> 51 </DrawingBrush> 52 </Setter.Value> 53 </Setter> 54 </Style>
3)端点移动的路径,这里将路径分成了4段,不分段会导致最后图片展开完成后是显示不完整的

1 <PathGeometry x:Key="path1"> 2 <PathFigure StartPoint="40,25"> 3 <PathFigure.Segments> 4 <PathSegmentCollection> 5 <LineSegment Point="540,25" /> 6 </PathSegmentCollection> 7 </PathFigure.Segments> 8 </PathFigure> 9 </PathGeometry> 10 <PathGeometry x:Key="path2"> 11 <PathFigure StartPoint="540,25"> 12 <PathFigure.Segments> 13 <PathSegmentCollection> 14 <LineSegment Point="540,340"/> 15 </PathSegmentCollection> 16 </PathFigure.Segments> 17 </PathFigure> 18 </PathGeometry> 19 <PathGeometry x:Key="path3"> 20 <PathFigure StartPoint="540,340"> 21 <PathFigure.Segments> 22 <PathSegmentCollection> 23 <LineSegment Point="40,340" /> 24 </PathSegmentCollection> 25 </PathFigure.Segments> 26 </PathFigure> 27 </PathGeometry> 28 <PathGeometry x:Key="path4"> 29 <PathFigure StartPoint="40,340"> 30 <PathFigure.Segments> 31 <PathSegmentCollection> 32 <LineSegment Point="40,25" /> 33 </PathSegmentCollection> 34 </PathFigure.Segments> 35 </PathFigure> 36 </PathGeometry>
4)动画,使用基于路径的动画

1 <Storyboard x:Key="fanOut"> 2 <PointAnimationUsingPath Storyboard.TargetName="aniCon" 3 Storyboard.TargetProperty="OpacityMask.Drawing.Geometry.Children[0].Figures[0].Segments[1].Point" 4 PathGeometry="{StaticResource path1}" 5 Duration="0:0:2" BeginTime="0:0:0"/> 6 <PointAnimationUsingPath Storyboard.TargetName="aniCon" 7 Storyboard.TargetProperty="OpacityMask.Drawing.Geometry.Children[0].Figures[1].Segments[1].Point" 8 PathGeometry="{StaticResource path2}" 9 Duration="0:0:2" BeginTime="0:0:2"/> 10 <PointAnimationUsingPath Storyboard.TargetName="aniCon" 11 Storyboard.TargetProperty="OpacityMask.Drawing.Geometry.Children[0].Figures[2].Segments[1].Point" 12 PathGeometry="{StaticResource path3}" 13 Duration="0:0:2" BeginTime="0:0:4"/> 14 <PointAnimationUsingPath Storyboard.TargetName="aniCon" 15 Storyboard.TargetProperty="OpacityMask.Drawing.Geometry.Children[0].Figures[3].Segments[1].Point" 16 PathGeometry="{StaticResource path4}" 17 Duration="0:0:2" BeginTime="0:0:6"/> 18 </Storyboard>
以上便是使用的代码了,这边用的都是Xaml来实现。动画使用按钮控件触发即可。
在实现过程中,也是遇到了各种问题,特别是Storyboard的TargetProperty的属性路径获取,试验了好久才找到正确的属性路径。当然,结果是喜人的。使用基于路径的动画来实现,代码还是挺多的,感觉挺复杂的,也许还可以简化,不过暂时就先这样了,后面要是有简化了再修改好了。