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

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

 


 

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

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

  

                获取 Microsoft Silverlight

↑点击开始
只要是通过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=BezierSegmentLineSegmentPoint属性指的是线段的终结点,BezierSegmentPoint3指的是曲线的终结点,Point1Point2分别指的是起始点控制点和结束点控制点的位置,就是用钢笔工具画曲线时拖动曲度的那两个点。当然了,每个线段的起始点为上一个线段的终结点。迷你表示法还有大小写分别表示绝对位置与相对位置,更多说明请参考下面链接。

详情请参考: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的子项就可以知道点与点之间的关系了,依次在点与点之间执行PointAnimationPointAnimationUsingPath让终结点从起始点运动到结束位置,就实现划线的效果了。

   曲线的话必须得用PointAnimationUsingPath来执行才显得自然一些,当然了,silverlight里是没有PointAnimationUsingPath动画的,所以得借助某外国达人写的PointAnimationUsingPath类,用法和WPF里差不多,不过个人觉得可以在Animation里直接来设置targettargetProperty还有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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/570581.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML 超链接

1.如何创建html超链接 <html> <body> <p> <a href"http://www.baidu.com" > website link</a> </p></body> </html>点击后跳转到baidu主页 2.超链接的title属性 <html> <body> <p> <a href&q…

用户注册信息实例

index.jsp用来接收用户输入的表单&#xff0c;其代码如下&#xff1a; <html> <body><form action"result.jsp" method"post"> 用户名&#xff1a;<input type"text" name"username"><br> 密码&#xf…

JSP调用request方法获取请求相关信息

index.jsp&#xff1a; <html> <body bgcolor"#FFFFF0"> 请求方式&#xff1a;<%request.getMethod() %><br> 请求的资源&#xff1a;<%request.getRequestURI() %><br> 请求用的协议&#xff1a;<%request.getProtocol() %&…

JSP实例-定时刷新页面

<html> <body> now the time is:<br> <% out.println(""new Date().toLocaleString()); //response对象中添加一个响应头&#xff0c;页面每20秒刷新一次 response.setHeader("Refresh","20");%> </body> </ht…

codeforces 540D Bad Luck Island (概率DP)

题意&#xff1a;会出石头、剪刀、布的人分别有r,s,p个&#xff0c;他们相互碰到的概率相同&#xff0c;输的人死掉&#xff0c;问最终活下去的人是三种类型的概率 设状态dp(i,j,k)为还有i个石头&#xff0c;j个剪刀&#xff0c;k个布时的概率&#xff0c;dp(r,s,p)1.0 状态转移…

jsp示例-response页面重定向

用户输入用户名和密码&#xff0c;如果用户名和密码分别是admin 和123&#xff0c;就重定向到success.jsp页面&#xff0c;否则重定向到登录页面。 index.jsp&#xff1a; <html> <body> 登录<br> <form action"next.jsp" method"post&qu…

day_01 解析简单的程序

就以上一节FirstProgram为例&#xff0c;请看下图&#xff1a;01、AndroidManifest.xml是整个项目的配置文件&#xff0c;非常重要&#xff0c;每个应用程序里必须存在的xml文件&#xff0c;且名字不可以改变&#xff0c;四大组件的使用必须在此处声明注册才可使用&#xff0c;…

时区与程序设计

时区的定义 我们使用经纬度[1]来标识地球上的任意一个点。 理论时区 不像纬度有赤道作为自然的起点&#xff0c;经度没有自然的起点而使用经过伦敦格林尼治天文台旧址的子午线作为起点。 理论时区的宽度是15&#xff0c;所以一共有 360 / 15 24 个时区&#xff0c;一天有 24 小…

JSP实例-彩色验证码

image.java用于产生彩色验证码&#xff0c;其代码如下&#xff1a; package test; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.ut…

P1678 烦恼的高考志愿

题目背景 计算机竞赛小组的神牛V神终于结束了万恶的高考&#xff0c;然而作为班长的他还不能闲下来&#xff0c;班主任老t给了他一个艰巨的任务&#xff1a;帮同学找出最合理的大学填报方案。可是v神太忙了&#xff0c;身后还有一群小姑娘等着和他约会&#xff0c;于是他想到了…

Java代码实现Fibonacci数列

Fibonacci数列 1.定义&#xff1a; 0, 1, 1, 2, 3, 5, 8, 13, 21, . . .; f0 0, f1 1, fn fn−1 fn−2 for n ≥ 2. 2.两种实现算法&#xff1a; 2.1递归&#xff08;recursive&#xff09; T(n)>2n/2证明: T(n)T(n−1)T(n−2)>2T(n−2)>22T(n−4)>...>2n/2T…

套路:想戒手机?试试把屏幕变灰

简评&#xff1a;园长试过了&#xff0c;瞬间不想再看手机&#xff0c;一股浓浓的性冷淡&#xff08;无能&#xff09;风&#xff0c;此时我只想去拥抱真实的世界。 我代表原作者。 我的手机已经变灰了&#xff0c;感觉很不错&#xff0c;不再沉迷。 为了戒掉手机瘾&#xff0c…

判断一个数是否存在于一个非递减的有序数列中 算法(Ordered Search Problem)

1. Description Given a list of nnumbers in non-decreasing order A{a1,a2,⋯,an}such that a1≤a2≤⋯≤anand a number x, the objective is to determine if xis present in the list A2. Algorithm Algorithm 1. Linear Search Algorithm Iterate through nnumbers to …

(4.12)全面解析-SQL事务+隔离级别+阻塞+死锁

30分钟全面解析-SQL事务隔离级别阻塞死锁 转自&#xff1a;https://blog.csdn.net/slowlifes/article/details/52752735 2016年10月07日 23:17:46 阅读数&#xff1a;1097阅读目录 概述&#xff1a;一、事务二、锁三、阻塞四、隔离级别五.死锁以前总是追求新东西&#xff0c;发…

mac启动mysql,apache,php

在用php编写网站之前&#xff0c;先要启动之前搭建好的环境。 1.启动mysql &#xff08;1&#xff09;在system preference的最底部有mysql控制图标&#xff1a; &#xff08;2&#xff09;点击mysql图标&#xff0c;启动mysql&#xff1a; 2.启动apache&#xff1a; 在term…

如何在命令长度受限的情况下成功get到webshell(函数参数受限突破、mysql的骚操作)...

0x01 问题提出 还记得上篇文章记一次拿webshell踩过的坑(如何用PHP编写一个不包含数字和字母的后门)&#xff0c;我们讲到了一些PHP的一些如何巧妙地绕过数字和字母受限的技巧&#xff0c;今天我要给大家分享的是如何在命令长度受限的情况下成功get到webshell&#xff0c;以及关…

iOS开发造轮子 | 通用占位图

https://www.jianshu.com/p/beca3ac24031 实际运用场景&#xff1a; 没网时的提示view&#xff0c;tableView或collectionView没内容时的展示view&#xff0c;以及其它特殊情况时展示的特定view。如&#xff1a; 常见的几种情况我的目标&#xff1a; 对以上几种情况的展示view做…

java 计算26个字母在一段文本中出现的频率(保留小数点后4位)

public class FrequencyCalculator {public static void main(String[] args){//定义需要计算字母出现频率的文本String text"some off#acebooksea3rl255 yinvestorssoldofftheirstockatthefirs" "tchancetheygotbutceomarkzuckerbergishangingontohissharesfor…

string赋值-单引号和双引号的区别(php)

在赋予一个string值的时候&#xff0c;可以用单引号或者双引号。 1.单引号和双引号的区别&#xff1a; 单引号&#xff1a;不会翻译变量。 双引号&#xff1a;会翻译变量&#xff0c;会将变量替换为之前赋予变量的值。 例子&#xff1a; &#xff08;1&#xff09;单引号&a…

Hibernate常用的Java数据类型映射到mysql和Oracle

研究了常用的Java基本数据类型在mysql和oracle数据库的映射类型。这里使用的是包装类型做研究&#xff0c;一般在hibernate声明的时候最好不要用基本类型&#xff0c;因为数据库中的null空数据有可能映射为基本类型的时候会报错&#xff0c;但是映射到包装类型的时候值为null&a…