通通玩blend美工(8)——动态绘制路径动画,画出个萌妹子~
原文:通通玩blend美工(8)——动态绘制路径动画,画出个萌妹子~
2年前我在玩Flex的时候就一直有一个疑问,就是如何来实现一个蚊香慢慢烧完的Loading动画呢?
刚经历了某甲方高强度一个月的洗礼后,这几天刚好闲下来,这个问题又浮现在我脑海里。于是经过几番思索纠结后,我发现了一个更好玩的效果,如下:
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 = ; 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 = ; /// <summary>
/// 新绘制的路径的集合
/// </summary>
List<Path> drawPathList = new List<Path>(); /// <summary>
/// 点集合索引
/// </summary>
int num = ; /// <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[].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[].Segments.Count)//画完一条线
{
if (pathNum < list.Count)
{
num = ;
PathPlay(list[pathNum++] as Path);//播放完毕就播放下一条线
return;
}
}
PathSegment item = PG.Figures[].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());
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();
//生成动画的路径形状
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());
PointAnimation PA2 = new PointAnimation();
PA2.To=(item as BezierSegment).Point2;
PA2.Duration=new Duration(TimeSpan.FromMilliseconds());
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。
觉得本文还可以的话要点击下面的推荐哦
喵~
通通玩blend美工(8)——动态绘制路径动画,画出个萌妹子~的更多相关文章
- 通通玩blend美工(1)——荧光Button
原文:通通玩blend美工(1)--荧光Button 最近老大出差去了,光做项目也有点烦,写点教程消遣消遣(注:此乃初级教程,所以第一个消遣是本人消遣,第二个是指供各位看官消遣...) 看着各位大虾出 ...
- 通通玩blend美工(6)上——仿iPhone滚动选择器的ListBox(UI设计)
原文:通通玩blend美工(6)上--仿iPhone滚动选择器的ListBox(UI设计) 好久没更新博客了,由于项目比较紧,期间收到不少园友的短消息,感谢大家对我的支持~~. 相信各位都在自己的神机 ...
- 通通玩blend美工(3)——可爱的云
原文:通通玩blend美工(3)--可爱的云 好久没有写这个系列的博客了,这里给个电梯吧,照顾新来的同学~~ 通通玩blend美工(1)——荧光Button 通通玩blend美工(2)——时钟 目前我 ...
- 通通玩blend美工(2)——时钟
原文:通通玩blend美工(2)--时钟 谢谢大家对我上一篇Blend的支持:通通玩blend美工(1)——荧光Button 再接再厉再来一篇~~! 这篇是建立在已经看得懂上一篇为基础来写的,有些细节 ...
- 通通玩blend美工(6)下——仿iPhone滚动选择器的ListBox(交互逻辑)
原文:通通玩blend美工(6)下--仿iPhone滚动选择器的ListBox(交互逻辑) 上一篇我们已经把界面画出来了,这篇我们就来制作交互的逻辑吧.上一篇的电梯: http://www.cnblo ...
- 通通玩blend美工(7)——简约而不简单的块
原文:通通玩blend美工(7)--简约而不简单的块 最近在研发一个WPF快速开发框架,满脑子都是各种逻辑各种模式,写一篇比较休闲娱乐的博客,宣泄下我对美工的热爱. 我一直以来有意无意在手机应用或者各 ...
- 通通玩blend美工(5)——旋转木马,交互性设计
原文:通通玩blend美工(5)--旋转木马,交互性设计 这一篇偏向于逻辑的比较多,放在这个系列里会不会欠妥呢?在中国交互性设计也是美工的份内职责哦~ 所以没有blend基础的人也可以看懂这篇文章,不 ...
- svg实现绘制路径动画
1,首先用svg绘制一条path路径,然后进行如下操作 ps: 下面是svg中两个属性及值的意义 stroke-dasharray是让你指定画出的线段每段的长度,第二个值是各段之间空隙的长度. str ...
- (数据科学学习手札85)Python+Kepler.gl轻松制作酷炫路径动画
本文示例代码.数据已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 Kepler.gl相信很多人都听说过,作为 ...
随机推荐
- ssl 内存泄露
http://i.mtime.com/chevalier/blog/1824652/ openssl内存分配 chevalier 发布于: 2009-04-20 10:31 openssl内存分配 ...
- Unity3d优化包的大小
http://wenku.baidu.com/link?url=MEUtNP6k1W7gXK2LcHdKXGqwoTD4HZDsBpsu9iFYjuL3WCIXgl2-rBHhBWP_zo5Xm4Yx ...
- Activity“ 阻止自动弹出软键盘”的方法 -尤其是对于Tab页下的!
我的activity是Tab页签下的~! 所以应把代码加在继承于TabActivity的那个activity中!!而不是由点击Tab页启动的那个activity <activity androi ...
- js进阶 10-11/12 表单伪类选择器的作用
js进阶 10-11 表单伪类选择器的作用 一.总结 一句话总结:能想到用伪类选择器来解决问题.如果能一次记住自然是最棒的. 1.表单伪类选择器分为哪两类? 表单元素和表单属性,表单元素例如inpu ...
- 前端切图:一个好看的表格css样式
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> ...
- Redis管理及监控工具
Redis管理及监控工具 Redis做为现在web应用开发的黄金搭担组合,大量的被应用,广泛用于存储session信息,权限信息,交易作业等热数据.做为一名有10年以上JAVA开发经验的程序员,工作中 ...
- 用Mochiweb打造百万级Comet应用,第一部分
http://www.iteye.com/topic/267028 原文:A Million-user Comet Application with Mochiweb, Part 1 参考资料:Com ...
- 【严肃脸】使用caffe实现色情图片的识别
前言 前几天看到了雅虎开源了一个色情图片的识别模型新闻,上Github一看,是基于caffe的.试了试,模型效果很赞.Github地址:https://github.com/yahoo/open_ns ...
- xml报错(xsd):Failed to read schema document
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLoc ...
- C# Color结构的各属性颜色对照表(转)
转自:http://blog.sina.com.cn/s/blog_454dc49501016q2p.html Color.AliceBlue 240,248,255 Color.LightSalmo ...