WPF使用Shape实现复杂线条动画
看到巧用 CSS/SVG 实现复杂线条光效动画的文章,便也想尝试用WPF的Shape配合动画实现同样的效果。ChokCoco大佬的文章中介绍了基于SVG的线条动画效果和通过角向渐变配合 MASK 实现渐变线条两种方式。WPF中的Shape与SVG非常相似,因此这种方式也很容易实现。但WPF中仅有的两种渐变画刷不包含角向渐变,本文使用了另外两种方式实现同样的效果。
在Avalonia的API文档中有看到ConicGradientBrush,应该可以用角向渐变的方式来实现。
首先看一下三种方式实现的效果(录制的gif中颜色存在一些偏差,动画有些卡顿,实际效果要好一些):
基于Polyline的线条动画效果
这种方式也是利用StrokeDashArray
实现虚线样式,然后通过动画设置StrokeDashOffset
来实现动画。首先,用Polyline
绘制一段折线:
<Polyline Points="240 20 140 20 140 100 0 100" Stroke="#ddd" />
这样,我们就得到一条这样的折线:
接下来,利用StrokeDashArray
实现与上边折线相同路径的虚线(点划线):
<Polyline Points="240 20 140 20 140 100 0 100" Stroke="red"
StrokeDashArray="20 30" />
StrokeDashArray
设置了虚线(点划线)中实线段的长度以及间隔,这里和SVG中的stroke-dasharray
略有不同,WPF中StrokeDashArray
使用的是相对值。例如此处设置的StrokeDashArray="20 30"
表示实线段长度为20,间隔为30,这些值是相对于线段的宽度StrokeThickness
。如果StrokeThickness=2
,那么实线段长度就是40个设备无关单位(Device Independent Units),间隔就是60DIUs。
当我们把间隔设置足够大时,就可以只看到一条实线段,这里折线中三条线段总长是320,因此把实线段设置20,间隔设置300:
<Polyline Points="240 20 140 20 140 100 0 100" Stroke="red"
StrokeDashArray="20 300" />
接下来就是借助StrokeDashOffset
来实现动画。
<Grid
Grid.Row="0"
Grid.Column="0"
Margin="5">
<Polyline Points="240 20 140 20 140 100 0 100" Stroke="#ddd" />
<Polyline
Points="240 20 140 20 140 100 0 100"
Stroke="red" StrokeThickness=""
StrokeDashArray="20 300">
<Polyline.Triggers>
<EventTrigger RoutedEvent="Polyline.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever" Storyboard.TargetProperty="StrokeDashOffset">
<DoubleAnimation
From="0"
To="-320"
Duration="0:0:3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Polyline.Triggers>
</Polyline>
</Grid>
与CSS/SVG实现的方式一样,WPF中也只能对整段虚线设置渐变色,无法对其中一段实线设置。要想实现渐变效果只能另寻他法。
基于多条线段的动画
最朴素的想法就是用一条渐变色的线段沿着折线的路径移动,但是最大的问题在于折线拐角处难以处理。最为粗暴简单的思路就是针对折线的三段准备三条线段,第一条线段动画即将结束时,第二条开始,第二条动画即将结束时第三条开始。
<Polyline Points="240 20 140 20 140 100 0 100" Stroke="#ddd" />
<Polyline
x:Name="polyline1"
Points="260 20 240 20"
Stroke="{StaticResource linearBrush}" />
<Polyline
x:Name="polyline2"
Points="140 0 140 20"
Stroke="{StaticResource linearBrush}" />
<Polyline
x:Name="polyline3"
Points="160 100 140 100"
Stroke="{StaticResource linearBrush}" />
这里有个细节需要注意,第1条线段向左移动刚好离开折线水平轨迹时,第2条线段才开始向下延垂直轨迹移动,并且移动速度一致,才能保证形成的移动的线段颜色连贯且长度不变。
<Storyboard x:Key="moveLines" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="polyline1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)">
<EasingDoubleKeyFrame KeyTime="00:00:00.800" Value="-100" />
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="-121" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="polyline2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)">
<EasingDoubleKeyFrame KeyTime="00:00:00.800" Value="0" />
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="20" />
<EasingDoubleKeyFrame KeyTime="00:00:01.8" Value="80" />
<EasingDoubleKeyFrame KeyTime="00:00:02" Value="101" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="polyline3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)">
<EasingDoubleKeyFrame KeyTime="00:00:01.8" Value="0" />
<EasingDoubleKeyFrame KeyTime="00:00:02" Value="-20" />
<EasingDoubleKeyFrame KeyTime="00:00:03" Value="-160" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
这样看效果并不明显,接下来就是需要用一个形状把完成动画的线段遮挡起来:
<Polygon Fill="#fff" Points="240,19 139,19 139,99 0,99 0,79 119,79 119,0 240,0 240,19 240,21 141,21 141,101 0,101 0,99 -20,99 -20,101 -20,122 161,122 161,41 260,41 260,19" />
这样基本实现了渐变色线条的动画效果,但终究不够优雅。
基于等腰三角形的动画
上一种方法中,在拐角处由两条线段配合的动画实现的效果,一条线段移出,另一条移入,连接起来刚好是个等腰直角三角形。
然后用线性渐变色填充三角形就可以实现移出的线段颜色和移入部分颜色相同。
<LinearGradientBrush x:Key="linearBrush" StartPoint="0 1" EndPoint="1 0">
<GradientStop Offset="0.25" Color="#399953" />
<GradientStop Offset="0.5" Color="#fbb300" />
<GradientStop Offset="0.75" Color="#d53e33" />
<GradientStop Offset="1" Color="#377af5" />
</LinearGradientBrush>
<Polygon
x:Name="trigle"
Fill="{StaticResource linearBrush}"
Points="240 19 240 40 220 19"/>
接下来就是三角形沿着轨迹移动的动画以及遮挡轨迹以外部分了。
<Storyboard x:Key="moveanimation" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="trigle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)">
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="20" />
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="-99" />
<EasingDoubleKeyFrame KeyTime="00:00:02" Value="-99" />
<EasingDoubleKeyFrame KeyTime="00:00:03" Value="-240" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="trigle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="0" />
<EasingDoubleKeyFrame KeyTime="00:00:02" Value="80" />
<EasingDoubleKeyFrame KeyTime="00:00:03" Value="80" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Grid Grid.Row="0" Grid.Column="1">
<Polyline Points="240 20 140 20 140 100 0 100" Stroke="#ddd" />
<Polygon
x:Name="trigle"
Fill="{StaticResource linearBrush}"
Points="240 19 240 40 220 19">
<Polygon.RenderTransform>
<TranslateTransform />
</Polygon.RenderTransform>
<Polygon.Triggers>
<EventTrigger RoutedEvent="Polygon.Loaded">
<BeginStoryboard Storyboard="{StaticResource moveanimation}" />
</EventTrigger>
</Polygon.Triggers>
</Polygon>
<Polygon Fill="#fff" Points="240,19 139,19 139,99 0,99 0,79 119,79 119,0 240,0 240,19 240,21 141,21 141,101 0,101 0,99 -20,99 -20,101 -20,122 161,122 161,41 260,41 260,19" d:IsHidden="True" />
</Grid>
小结
基于Polyline的线条StrokeDashOffset
的方式最为灵活简洁,不仅适用于直角折线,还适用于各种曲线。如果把此处的Polyline换成一个Ellipse,就可以实现简单的转圈圈等待的动效,但其不足在于线条样式美化空间有限。
基于多条线段的动画可以美化线条,但只适用于Polyline
或者直线组成的Path
,一旦存在曲线就不适用了。
基于等腰三角形的动画可以看做是基于多条线段的动画的一种特殊场景,局限性较大,仅适用于带直角的折线。
WPF使用Shape实现复杂线条动画的更多相关文章
- 【Web动画】SVG 实现复杂线条动画
在上一篇文章中,我们初步实现了一些利用基本图形就能完成的线条动画: [Web动画]SVG 线条动画入门 当然,事物都是朝着熵增焓减的方向发展的,复杂线条也肯定比有序线条要多. 很多时候,我们无法人工去 ...
- 【Web动画】SVG 线条动画入门
通常我们说的 Web 动画,包含了三大类. CSS3 动画 javascript 动画(canvas) html 动画(SVG) 个人认为 3 种动画各有优劣,实际应用中根据掌握情况作出取舍,本文讨论 ...
- PPT制作线条动画
0.小叙闲言 今天在用PPT做动画的时候小有心得,百度了一下线条动画制作,有一个贴子里面的讨论,也给了我一些灵感,贴子地址:http://www.rapidbbs.cn/thread-24577-1- ...
- 炫酷线条动画--svg
我们经常可以在一些页面看到看起来很酷的线条动画,有些可以用css实现,有些css就无能为力了,今天来研究另一种实现方式,svg 如果对svg是什么还不了解的话,可以先去看看svg的基础教程: 一般对于 ...
- WPF实现QQ群文件列表动画(二)
上篇(WPF实现QQ群文件列表动画(一))介绍了WPF实现QQ群文件列表动画的大致思路,结合我之前讲过的WPF里ItemsControl的分组实现,实现起来问题不大,以下是效果图: 其实就是个List ...
- SVG动画实践篇-无中生有的线条动画
git: https://github.com/rainnaZR/svg-animations/tree/master/src/pages/step2/path 说明 这个动画实现的是线条动画,主要用 ...
- WPF中自动增加行(动画)的TextBox
原文:WPF中自动增加行(动画)的TextBox WPF中自动增加行(动画)的TextBox WPF中的Textbox控件是可以自动换行的,只要设置TextWrapping属性为"Wrap& ...
- WPF入门(三)->几何图形之线条(LineGeometry)
原文:WPF入门(三)->几何图形之线条(LineGeometry) 前一章我们对wpf的xaml语言有了一定的了解,那么我们现在开始来学习如何使用wpf来画出几何图形. LineGeometr ...
- WPF中的PathAnimation(路径动画)
原文:WPF中的PathAnimation(路径动画) WPF中的PathAnimation(路径动画) ...
- 线条之美,玩转SVG线条动画
线条之美,玩转SVG线条动画 作者:AlloyTeam www.alloyteam.com/2017/02/the-beauty-of-the-lines-break-lines-svg-animat ...
随机推荐
- Regex中Replace方法的简单实用
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Python拷贝、移动、重命名、删除文件和文件夹----shutil
拷贝 # 拷贝文件import shutil # 语法: shutil.copy(src, dst) '''示例 将 a 文件夹中的 a.txt 拷贝到 b 文件夹 ''' shutil.copy(' ...
- openGauss社区入门(openGauss-定时任务)
为什么要使用定时任务 在一个固定的时间点活间隔一段时间需要频繁触发某一动作,为了使用便捷,有了定时任务,极大的减少了工作的重复性,提高了效率. 定时任务的内容 基于定时任务产生的背景,定时任务内容包括 ...
- react native 0.73 配置 react-native-fs
安装react-native-fs npm npm install react-native-fs --save yarn yarn add react-native-fs 安卓配置 android/ ...
- Mysql之innodb架构
Innodb存储引擎的架构 内存结构 Bufer Pool 缓冲池是主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载 ...
- redis 简单整理——redis 准备篇[一]
前言 简单整理一下redis. 正文 为什么使用redis? 速度快 1.1 内存执行 1.2 c语言编写,速度相对快一些 1.3 单线程,比较符合这种存储模式 2 丰富的数据结构 3 丰富的功能机制 ...
- Vue 3 进阶用法:异步组件
一.代码分割 一个大型前端应用,如果所有代码都放在单一文件,体积会特别大,下载时间长,白屏时间久,用户体验差. 代码分割是一种有效的优化方式.提前把代码切分为多个小块,只下载当前必需的部分,用到哪块下 ...
- Django框架——csrf跨站请求伪造、csrf校验、csrf相关装饰器、auth认证、auth认证相关模块及操作
csrf跨站请求伪造 钓鱼网站:模仿一个正规的网站 让用户在该网站上做操作 但操作的结果会影响到用户正常的网站账户 但是其中有一些猫腻 eg:英语四六级考试需要网上先缴费 但是你会发现卡里的钱扣了但是 ...
- HL7传输协议
HL7消息通过各种TCP/IP传输发送,其中一些包括: 下层协议(LLP) 文件传输协议(FTP) 简单对象访问协议(SOAP) 简单邮件传输协议(SMTP) 尽管HL7可以使用多种传输协议进行数据传 ...
- EventBridge 特性介绍|以 IaC 的方式使用 EventBridge
简介:本文将重点介绍 EventBridge 和 IaC 的重点概念和特性,然后演示如何应用 IaC 理念自动化部署 EventBridge 来使用这些概念和特性. 作者:王川(弗丁) 引言 Eve ...