通通玩blend美工(8)——动态绘制路径动画,画出个萌妹子~
原文:通通玩blend美工(8)——动态绘制路径动画,画出个萌妹子~


  2年前我在玩Flex的时候就一直有一个疑问,就是如何来实现一个蚊香慢慢烧完的Loading动画呢?  

  刚经历了某甲方高强度一个月的洗礼后,这几天刚好闲下来,这个问题又浮现在我脑海里。于是经过几番思索纠结后,我发现了一个更好玩的效果,如下:

  

↑点击开始
只要是通过path来表示的都可以画出来哦亲~如果好好构思一下是可以实现很震撼的效果的,你想到了没?

 

1.总体思路


  下面我就来分析一下实现思路。  

  仔细观察下,

  1:遍历出所有的Path。

  2:把各个Path分解成各种点。

  3:依次对各个点执行PointAnimation动画(直线执行PointAnimation,曲线执行PointAnimationUsingPath)。

  

2.详细设计


  首先,我们得画一个路径作为动画的样本路径。

1、准备萌妹子一枚

打开后,转成路径,如下:

参数:

确定后得到

可以手动删除一些无用的路径。

然后导出路径

              

打开导出的Xaml将Path都Copy出来用。

2、遍历出萌妹子的各种轮廓

  这里我之前写过一个遍历一个对象的可视树下所有的某类型的子对象的方法(wpf移植过来的为了适应,临时小改了一下)。

       List<Path> list = new List<Path>();/// <summary>/// 遍历某对象下某类型的所有子元素/// </summary>/// <param name="myVisual">遍历的对象</param>/// <param name="type">子元素的类型</param>public void EnumVisual(DependencyObject myVisual, Type type){for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++){DependencyObject childVisual = (DependencyObject)VisualTreeHelper.GetChild(myVisual, i);if (childVisual != null){if (childVisual.GetType() == type){list.Add(childVisual as Path);}EnumVisual(childVisual, type);}}return;}    

然后

EnumVisual(Group, typeof(Path));

其中Group为包含所有Path的容器,这样list里就充满了萌妹子的轮廓。

3、把每一条Path都分割成各种点的表示方式

  这里我们先来了解一下Path的路径标记语法。其实,Path的线段是有两种表示方法的,如下:

第一种:

<Path Data="M96,200 L176,288 C176,288 272,232 248,208" Fill="#FFF8F8F8" Stroke="Black"/>

第二种:   

      <Path x:Name="path" Fill="#FFF8F8F8" Stroke="Black"><Path.Data><PathGeometry><PathFigure StartPoint="96,200"><LineSegment Point="176,288"/><BezierSegment Point3="248,208" Point2="272,232" Point1="176,288"/></PathFigure></PathGeometry></Path.Data></Path>    

  这两段代码表示的是同样的路径。其中M=StartPoint,L=LineSegment,C=BezierSegment,LineSegment的Point属性指的是线段的终结点,BezierSegment的Point3指的是曲线的终结点,Point1和Point2分别指的是起始点控制点和结束点控制点的位置,就是用钢笔工具画曲线时拖动曲度的那两个点。当然了,每个线段的起始点为上一个线段的终结点。迷你表示法还有大小写分别表示绝对位置与相对位置,更多说明请参考下面链接。

详情请参考:http://msdn.microsoft.com/zh-cn/library/ms752293.aspx

  我们遍历出来的Path其实都是用第一种表示方法表示的,这样不方便我们后台来分解解析。我们得把第一种表示方法装换为第二种。这里我们得借用国外大侠分享的类:

http://stringtopathgeometry.codeplex.com/

这个东西可以很方便的实现这两种格式的转换,如下:

StringToPathGeometryConverter _s = new StringToPathGeometryConverter();
PathGeometry PG = _s.Convert(path.Data.ToString());

这样转换出来的PG就是第二种表示方法了。

  通过遍历第二种表示方法里面PathFigure的子项就可以知道点与点之间的关系了,依次在点与点之间执行PointAnimation和PointAnimationUsingPath让终结点从起始点运动到结束位置,就实现划线的效果了。

  曲线的话必须得用PointAnimationUsingPath来执行才显得自然一些,当然了,silverlight里是没有PointAnimationUsingPath动画的,所以得借助某外国达人写的PointAnimationUsingPath类,用法和WPF里差不多,不过个人觉得可以在Animation里直接来设置target和targetProperty还有Begin方法,这一点比微软写的更好用。

详情请参看:http://www.codeproject.com/Articles/30819/Animation-Along-a-Path-for-Silverlight

好了,直接上代码:

全局变量

/// <summary>/// 存储遍历到的Path样本/// </summary>List<Path> list = new List<Path>();/// <summary>/// Path样本索引/// </summary>int pathNum = 0;/// <summary>/// 新绘制的路径的集合/// </summary>List<Path> drawPathList = new List<Path>();/// <summary>/// 点集合索引/// </summary>int num = 0;/// <summary>/// 当前绘制路径的样本Path /// </summary>
        PathGeometry PG;/// <summary>/// 当前绘制路径中的点集合  /// </summary>
        PathFigure PF;/// <summary>/// 当前绘制路径中的结束点/// </summary>Point endPoint;

画线方法

 /// <summary>/// 开始绘制一条路径/// </summary>/// <param name="path">路径样本</param>private void PathPlay(Path path){Path ph = new Path();//当前绘制的路径
            drawPathList.Add(ph);ph.Stroke = new SolidColorBrush(Colors.Black);drawGrid.Children.Add(ph);//添加进画布
PathGeometry thisPG = new PathGeometry();//动画路径的数据ph.Data = thisPG;StringToPathGeometryConverter _s = new StringToPathGeometryConverter();PG = _s.Convert(path.Data.ToString());//读取样本路径,分解段PF = new PathFigure();//创建集合endPoint = PF.StartPoint = PG.Figures[0].StartPoint;//设置起始点,一开始的终结点为起始点
            thisPG.Figures.Add(PF);Play();//开始绘制分段的路径
}/// <summary>/// 绘制路径的一段/// </summary>private void Play(){try{if (pathNum >= list.Count)//画完所有的路径
                {FillColor();//开始填充颜色Group.Visibility = Visibility.Visible;                   return;}else if (num >= PG.Figures[0].Segments.Count)//画完一条线
                {if (pathNum < list.Count){num = 0;PathPlay(list[pathNum++] as Path);//播放完毕就播放下一条线                    return;}}PathSegment item = PG.Figures[0].Segments[num++];//读取下一个点if (item.ToString().Contains("Line"))//如果这个点是直线
                {LineSegment _ls = new LineSegment();_ls.Point = endPoint;                    PathSegment PS = _ls;//创建一条直线的初始状态点
                    PointAnimation PA = new PointAnimation();//动画到读取的点的位置PA.To=(item as LineSegment).Point;PA.Duration = new Duration(TimeSpan.FromMilliseconds(50));PA.Completed += new EventHandler((sender1, e1) =>//播放完毕后进行递归,绘制下一条线
                    {Play();});PF.Segments.Add(PS);//添加点//PS.BeginAnimation(LineSegment.PointProperty, PA);Storyboard sb = new Storyboard();sb.Children.Add(PA);Storyboard.SetTarget(PA, PS);Storyboard.SetTargetProperty(PA, new PropertyPath("Point"));sb.Begin();//开始动画endPoint = (item as LineSegment).Point;//记录终结点
}else if (item.ToString().Contains("Bezier"))//如果这个点是贝尔曲线
                {BezierSegment _bs = new BezierSegment();_bs.Point1 = _bs.Point2 = _bs.Point3 = endPoint;PathSegment PS = _bs;PointAnimationUsingPath PA = new PointAnimationUsingPath();//创建终结点的路径动画,曲线要严格按照路径来运动PA.Target = PS;PA.TargetProperty = new PropertyPath("Point3");PA.Duration = TimeSpan.FromMilliseconds(50);//生成动画的路径形状PathGeometry newPG = new PathGeometry();PathFigure newPF = new PathFigure();//创建集合newPF.StartPoint = endPoint;//s设置起始点和每次动画的种植点
                    newPG.Figures.Add(newPF);BezierSegment _bs1 = new BezierSegment();_bs1.Point1 = (item as BezierSegment).Point1;_bs1.Point2 = (item as BezierSegment).Point2;_bs1.Point3 = (item as BezierSegment).Point3;newPF.Segments.Add(_bs1);PA.PathGeometry = newPG;PA.Completed += new EventHandler((sender1, e1) =>{Play();});PA.Begin();//同样对控制点也要进行一般的动画PointAnimation PA1 = new PointAnimation();PA1.To=(item as BezierSegment).Point1;PA1.Duration=new Duration(TimeSpan.FromMilliseconds(500));PointAnimation PA2 = new PointAnimation();PA2.To=(item as BezierSegment).Point2;PA2.Duration=new Duration(TimeSpan.FromMilliseconds(500));PF.Segments.Add(PS);//PS.BeginAnimation(BezierSegment.Point3Property, PA);//PS.BeginAnimation(BezierSegment.Point1Property, PA1);//PS.BeginAnimation(BezierSegment.Point2Property, PA2);Storyboard sb = new Storyboard();//sb.Children.Add(PA);//Storyboard.SetTarget(PA, PS);//Storyboard.SetTargetProperty(PA, new PropertyPath("Point"));//sb.Begin();//开始动画endPoint = (item as BezierSegment).Point3;}}catch{}}

方法里用了各种递归是因为处理完一条Path的所有动画后执行下一条Path的动画,而每一条Path里的每一小段也得依次处理, 要让一序列的动画依次播放,得在动画播放完毕后再播放下一段动画,各位大虾有没有更好的方法来依次播放一序列动画呢??

后记


  原版是Wpf的,wpf自带了PointAnimationUsingPath动画,所以实现起来代码少得多了。接下来我打算优化后把它封成一个行为,方便以后使用。

  文中出现了这么多外国牛人的文章,当然了以小弟的强烈爱国情怀是无法完全理解,所以特别谢http://www.cnblogs.com/beniao/archive/2010/05/26/1736446.html。

觉得本文还可以的话要点击下面的推荐哦喵~

  

  

posted on 2018-08-03 00:26 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/9411026.html

通通玩blend美工(8)——动态绘制路径动画,画出个萌妹子~相关推荐

  1. 通通玩blend美工(5)——旋转木马,交互性设计

    这一篇偏向于逻辑的比较多,放在这个系列里会不会欠妥呢?在中国交互性设计也是美工的份内职责哦~ 所以没有blend基础的人也可以看懂这篇文章,不过要用到初中的几何知识哦~亲 相信很多人都在手机或者网页上 ...

  2. 通通玩blend美工(6)下——仿iPhone滚动选择器的ListBox(交互逻辑)

    原文:通通玩blend美工(6)下--仿iPhone滚动选择器的ListBox(交互逻辑) 上一篇我们已经把界面画出来了,这篇我们就来制作交互的逻辑吧.上一篇的电梯: http://www.cnblo ...

  3. php图片动画源码,JavaScript_jQuery插件ImageDrawer.js实现动态绘制图片动画(附源码下载),ImageDrawer.js是一款可以实现动 - phpStudy...

    jQuery插件ImageDrawer.js实现动态绘制图片动画(附源码下载) ImageDrawer.js是一款可以实现动态绘制图片动画的jQuery插件.通过ImageDrawer.js插件,你可 ...

  4. Python测试题(绘制柱状图、画出sin函数图像、散点图、pandas实现列表)

    Python 1. 绘制一个柱状图,写出代码,要求: x = [1,2,3,4,5,6,7,8] y = [3,1,4,5,8,9,7,2] 图形最后形式如下图所示: import matplotli ...

  5. python画动态爱心-使用Python画出小人发射爱心的代码

    我就废话不多说了,直接上代码吧! #2.14 from turtle import * from time import sleep def go_to(x, y): up() goto(x, y) ...

  6. Silverlight 2.5D RPG游戏技巧与特效处理:(二十一)自定义路径动画

    一直在想应该用什么作为<Silverlight 2.5D RPG游戏技巧与特效处理系列教程>的终结,既要实用而不拖泥带水:又要通用而不哗众取宠.于是一不小心便成就了我一个未了心愿:一切基于 ...

  7. Silverlight 2.5D RPG游戏技巧与特效处理:自定义路径动画

    一直在想应该用什么作为<Silverlight 2.5D RPG游戏技巧与特效处理系列教程>的终结,既要实用而不拖泥带水:又要通用而不哗众取宠.于是一不小心便成就了我一个未了心愿:一切基于 ...

  8. 【Python应用】Python+Kepler.gl轻松制作酷炫路径动画

    文章来源于Python大数据分析,作者费弗里 本文示例代码.数据已上传至Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 ...

  9. python炫酷动画源代码_(数据科学学习手札85)Python+Kepler.gl轻松制作酷炫路径动画...

    1 简介 Kepler.gl相信很多人都听说过,作为Uber几年前开源的交互式地理信息可视化工具,kepler.gl依托WebGL强大的图形渲染能力,可以在浏览器端以多种形式轻松展示大规模数据集. 图 ...

最新文章

  1. linux 内核 config_localversion_auto,关于CONFIG_LOCALVERSION_AUTO设置去掉内核版本号SVN后缀...
  2. [置顶]       webservice系列2---javabeanhandler
  3. BIND 子域授权的实现和区域转发实现
  4. React路由---react-router-dom、获取路由参数、ant design ui组件、fetch发送请求(默认不能跨域)、Switch...
  5. 批处理命令 / 延迟环境变量扩展
  6. ubuntu系统文件删除/复制/移动
  7. vue3.0 execle 导出功能实现
  8. 查看 chrome 浏览器中的 Headers
  9. python热狗大战
  10. i386和i686的区别
  11. 大数据分析技术与应用
  12. Mysql 分表分区
  13. 电脑时间调到2099年,会发生什么
  14. Unity相机设置CullingMask
  15. python可以取代excel吗_python能彻底取代excel吗?
  16. AFD在CentOS环境中部署
  17. Java通过freemaker实现健康报告生成(包含列表、列表合并列)
  18. GitLab使用手册
  19. 维汉在线翻译电脑版_支持汉语维吾尔语互译_维文翻译汉语和维语学习
  20. 解决 XCode6 在 iOS7 系统上出现部分黑屏与不适配问题

热门文章

  1. oracle连接数达不到上限,Oracle超出最大连接数问题及解决(转)
  2. ThreadLocal初识
  3. python列表转换成数字_python 字母转成数字Python操作列表的常用方法总结
  4. Linux下文件的压缩和解压
  5. 基于Java+SpringMvc+vue+element实现高效学生社团平台管理
  6. 2021计算机专业考408的学校,2021考研:计算机考研408是什么?统考学校有哪些?...
  7. 用python做频数分析_使用Python进行描述性统计
  8. java使用计算器完成加法、减法运算
  9. java union pay 代码_Java标记了union / sum类型
  10. C++ 转换构造函数