WPF Path实现虚线流动效果

原文: WPF Path实现虚线流动效果

最近闲来无事,每天上上网,看看博客生活也过得惬意,这下老总看不过去了,给我一个任务,叫我用WPF实现虚线流动效果,我想想,不就是虚线流动嘛,这简单于是就答应下来了,谁也没想到这简单的东西搞了3天没搞定,最后搞定了居然是那么的简单,自己是想得太复杂了,哎,脑子生锈了,废话不多说,进入这3天的无脑思考中。

  思路1:

  根据老总的说法,他只要我实现效果就行了,那好,我就偷一下懒,用Line实现,用一个Line数组,装入一定量的Line对象,使他们间隔相同的距离,开启多线程,使得每一个Line对象每秒向前移动 1/3,但是最后一个Line向前移动的时候,需要每次减掉 1/3的长度,直到长度为0,这样才让人有一种视觉错觉虚线在向某个方向流动,当最后一个Line长度为0的时候,把最后一个对象移动到数组的第一位,其他对象依次想后移,下面是代码:

  1 Line[] line = new Line[11];
2 double width;
3 double height;
4 int i = 0;
5 public MainWindow()
6 {
7 InitializeComponent();
8 }
9 /// <summary>
10 /// 线段向某方向移动
11 /// </summary>
12 private void LineMove()
13 {
14 double x1 = width / 20;
15 double x2 = x1 / 3;
16 for (int i = 10; i >=0; i--)
17 {
18 if (i == 10)
19 {
20 if (line[i].X1 >= line[i].X2)//如果最后一条长度为0的时候,就移动到第一位
21 {
22 LineArryMove();
23 }
24 line[i].X1 += x2;
25 }
26 else
27 {
28 line[i].X1 += x2;
29 line[i].X2 += x2;
30 }
31
32 }
33 }
34 /// <summary>
35 /// 最后一个对象移到第一位
36 /// </summary>
37 private void LineArryMove()
38 {
39 double x1 = width / 20;
40 double x2 = x1 / 3;
41 Line temp = line[0];
42 line[0] = line[10];
43 for (int i = 0; i < 10; i++)
44 {
45 Line temp1 = line[i + 1];
46 line[i + 1] = temp;
47 temp = temp1;
48 }
49 for (int i = 1; i<11; i++)
50 {
51 line[i].X1 += x2;
52 line[i].X2 += x2;
53 }
54 line[0].X1 = x2;
55 line[0].X2 = x2 + x1;
56 }
57 /// <summary>
58 /// 画出一条虚线
59 /// </summary>
60 private void LineDraw()
61 {
62 height=this.canvas.ActualHeight;
63 width = this.canvas.ActualWidth;
64 double x1 = width / 20;
65 double x2 = x1 / 3;
66 for (int i = 0; i < 11; i++)
67 {
68 line[i] = new Line();
69 line[i].Stroke = Brushes.Red;
70 line[i].StrokeThickness = 3;
71 line[i].X1 = (i + 1) * x2 + i * x1;
72 line[i].X2 = (i + 1) * x2 + (i+1)* x1;
73 line[i].Y1 = height / 2;
74 line[i].Y2 = height / 2;
75 this.canvas.Children.Add(line[i]);
76 }
77 }
78 /// <summary>
79 /// 开启多线程
80 /// </summary>
81 private void ThreadStart()
82 {
83 Thread P_th = new Thread(//建立线程
84
85 () =>//使用lambda表达式
86 {
87
88 while (true)//开始无限循环
89 {
90
91 this.Dispatcher.BeginInvoke(//在窗体线程中执行相关代码
92
93 System.Windows.Threading.DispatcherPriority.Normal,//设置线程优先级
94
95 (ThreadStart)(() =>//使用lambda表达式
96 {
97
98 LineMove();
99
100 }));
101
102 Thread.Sleep(1000);//线程挂起1秒钟
103 i++;
104
105 }
106
107 });
108
109 P_th.IsBackground = true;//设置线程为后台线程
110
111 P_th.Start();//线程开始
112 }
113 private void button1_Click(object sender, RoutedEventArgs e)
114 {
115 LineDraw();
116 }
117
118 private void button2_Click(object sender, RoutedEventArgs e)
119 {
120 ThreadStart();
121 }

  好吧,这样效果是实现了,但也仅仅是测试一下效果,要是曲线,或者一些不规则的线段的话,肯定不能这样实现,又想了一下,WPF可以实现动画效果,那我们试试用动画实现看看,这就涉及到了路径动画的实现,路径动画,也就是某个对象沿着一条路径运动,这就有了下一个思路。

  思路2:

  还是用Line作为填充对象,每一个对象的的运动周期是一样的,但是动画开始的时间不一样,设置间隔递增的开始时间,这样开始动画的时候,每个Line都会依次出现,这样就就有了流动的效果,但是还有一个问题,就是它有一个填充时间,当第一个对象的一个周期后,这条虚线才被填充完毕,- -这和老总说的有出入,也不知道能不能通过,下面是主要代码:

 1    /// <summary>
2 ///
3 /// </summary>
4 /// <param name="btnPath"></param>
5 /// <param name="xNum">第N个对象</param>
6 /// <param name="sleepTime">间隔时间</param>
7 /// <param name="pathLine">Path对象</param>
8 /// <param name="DuTime">动画时间</param>
9 private void AnimationStart(Line btnPath, int xNum, int sleepTime,Path pathLine,int DuTime)
10 {
11
12 double realTime = ((double)sleepTime) / ((double)1000);
13 string strTranslate = "translate"+xNum;
14 string strRote = "rotate"+xNum;
15
16 //btnPath.Width = 20;
17 //btnPath.Height = 5;
18 btnPath.Stroke = Brushes.Red;
19 btnPath.X1 = 0;
20 btnPath.X2 = 20;
21 btnPath.StrokeThickness = 5;
22
23 Canvas.SetTop(btnPath, -2.5);
24 Canvas.SetLeft(btnPath, -10);//为了使对象与路径更加重合,可自己调节初始坐标
25
26 btnPath.RenderTransformOrigin = new Point(0.5, 0.5);
27
28 TranslateTransform translate = new TranslateTransform();
29 RotateTransform rotate = new RotateTransform();
30 TransformGroup group = new TransformGroup();
31
32 group.Children.Add(rotate);//先旋转
33 group.Children.Add(translate);//再平移
34
35 NameScope.SetNameScope(this, new NameScope());
36
37 this.RegisterName(strTranslate, translate);
38 this.RegisterName(strRote, rotate);
39
40 btnPath.RenderTransformOrigin = new Point(0.5, 0.5);
41 this.canvas.Children.Add(btnPath);
42
43 btnPath.RenderTransform = group;
44 //设置物体X轴的目标
45 DoubleAnimationUsingPath animationX = new DoubleAnimationUsingPath();
46 animationX.PathGeometry = pathLine.Data.GetFlattenedPathGeometry();
47 animationX.Source = PathAnimationSource.X;
48 animationX.Duration = new Duration(TimeSpan.FromSeconds(DuTime));
49 animationX.BeginTime = TimeSpan.FromSeconds(xNum * realTime);
50 animationX.RepeatBehavior = RepeatBehavior.Forever;
51 //设置物体Y轴的目标
52 DoubleAnimationUsingPath animationY = new DoubleAnimationUsingPath();
53 animationY.PathGeometry = pathLine.Data.GetFlattenedPathGeometry();
54 animationY.Source = PathAnimationSource.Y;
55 animationY.Duration = animationX.Duration;
56 animationY.BeginTime = TimeSpan.FromSeconds(xNum * realTime);
57 animationY.RepeatBehavior = RepeatBehavior.Forever;
58
59 //设置物体的旋转角度
60 DoubleAnimationUsingPath animationAngle = new DoubleAnimationUsingPath();
61 animationAngle.PathGeometry = pathLine.Data.GetFlattenedPathGeometry();
62 animationAngle.Source = PathAnimationSource.Angle;
63 animationAngle.Duration = animationX.Duration;
64 animationAngle.BeginTime = TimeSpan.FromSeconds(xNum * realTime);
65 animationAngle.RepeatBehavior = RepeatBehavior.Forever;
66
67 translate.BeginAnimation(TranslateTransform.XProperty, animationX);
68 translate.BeginAnimation(TranslateTransform.YProperty, animationY);
69 rotate.BeginAnimation(RotateTransform.AngleProperty, animationAngle);
70
71 }

  现在最大的一个问题来了,都传说WPF的动画很耗资源,一看CPU,哇,I5的处理器都达到百分之15,这不是坑爹么,这怎么拿出去见人啊,又到了思考的时候,CPU该怎么降下来,试了很多种方法,都是差不多,动画对象一多,CPU就高,当思路进入死胡同的时候,想出来就不那么容易了 - -,就这样耗费了两天时间,突然灵机一闪,我去MSDN一个个的查看Path的方法和属性,这一看,好吧,我承认自己脑残了。。。。

  Path主要属性:

  StrokeThickness 线段的粗细

  Data 路径数据  如:Data=“Data="M25,522 C25,522 6.5,322.5 102.5,319.5 198.5,316.5 245.49957,361.5 369.4992,207.5 493.49883,53.5 468.49891,29.5 559.49864,59.5 650.49837,89.5 692.49827,292.49995 698.49825,304.49996 704.49823,316.49996 698.49823,484.49999 615.49848,501.5 532.49872,518.5 317.4995,543.5 251.49967,516.5 185.49983,489.49999 789.49832,175.49996 502.49904,127.49994"”;

  StrokeDashArray 虚线的设置 如:StrokeDashArray=“10,5”;意思就是把Path分成若干线段,每一段是10,间隔为5,。

  StrokeDashOffset 线段的偏移量!好吧,这就是我们所需要的最重要属性。减去或加上一个数,线段就会向某个方向移动一段距离,要想做成移动的虚线,只要循环设置StrokeDashOffset的值就可以了,代码:

 1         private void ThreadStart()
2 {
3 Thread P_th = new Thread(//建立线程
4
5 () =>//使用lambda表达式
6 {
7
8 while (flag)//开始无限循环
9 {
10
11 this.Dispatcher.BeginInvoke(//在窗体线程中执行相关代码
12
13 System.Windows.Threading.DispatcherPriority.Normal,//设置线程优先级
14
15 (ThreadStart)(() =>//使用lambda表达式
16 {
17 this.path1.StrokeDashOffset -=10;
18
19 }));
20
21 Thread.Sleep(500);//线程挂起
22 }
23
24 });
25
26 P_th.IsBackground = true;//设置线程为后台线程
27
28 P_th.Start();//线程开始
29 }

  本文来自01_code的博客,原文地址:http://www.cnblogs.com/01codeworld/archive/2012/02/17/loce.html

猜你喜欢

转载自www.cnblogs.com/lonelyxmas/p/9577016.html
今日推荐