WPF利用动画实现圆形进度条

原文:WPF利用动画实现圆形进度条

  这是我的第一篇随笔,最近因为工作需要,开始学习WPF相关技术,自己想实现以下圆形进度条的效果,逛了园子发现基本都是很久以前的文章,实现方式一般都是GDI实现的,想到WPF中动画效果不错,于是自己研究了一下,还真让我做出来了,废话不多说了,先上效果。

WPF利用动画实现圆形进度条

  这个效果是不是还不错?这里面实现了数字实时显示以及根据进度进行自动渐变的效果。实现原理其实很简单,利用WPF动画,其中主要元素有border(实现里外层圆的效果),Arc扇面(就是用来实现外层填充效果的),Label(用来显示进度百分比)。

1.实现里外双层圆背景效果

  这里我用了两个border实现,将两个border的CornerRadius设置为500,这样保证他们是两个圆(这里不用Ellipse是我觉得border可能更加省资源),然后将他们他们的宽度设置为100和80,让他们作为同心圆。其他设置主要为了美观此处不再多说,一会上代码即可。

2.利用Arc实现填充效果

  说起这个Arc还真是个好东西,之前只是知道它是个扇面,但是没想到还可以实现弧度填充,这得益于它的ArcThickness可以设置为小数,这个具体数值可以在blend中自己调节一下,ArcThicknessUnit设置为Percent,意思是单位是百分比。然后利用Arc的StartAngle和EndAngle就可以轻松实现进度填充了。

3.利用Label实现进度显示

  最后在中间放置一个Label,然后将它的Text属性绑定到Arc的EndAngle上,之后自己写个Convert将角度转化为百分比即可。

4.动画的实现

  剩下的就可以利用blend做个动画,动画效果十分简单,开始时间,结束时间,开始角度,结束角度。这样简单的填充效果就实现了,最后还要实现渐变效果,好吧,其实也比较简单,同样的开始时间,结束时间,开始颜色,结束颜色,然后两个动画的时间间隔相同就好,这样效果比较同步。

注意:最后说一句,用ViewBox将整个效果框起来,这样以后无论你怎么拖拽这个空间,内部都不会出现变形的效果了。

代码如下:

WPF利用动画实现圆形进度条WPF利用动画实现圆形进度条
 1 <UserControl x:Class="MyUserControlLibrary.WaitingAndProgress"
 2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
 5              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
 6              xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
 7              xmlns:local ="clr-namespace:MyUserControlLibrary"
 8              mc:Ignorable="d" 
 9              d:DesignHeight="100" d:DesignWidth="100" Loaded="UserControl_Loaded">
10     <UserControl.Resources>
11         <local:ConverterCircleToPercent x:Key="converter"/>
12         <Storyboard x:Key="MainStoryboard" RepeatBehavior="Forever">
13             <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="ShowArea">
14                 <EasingDoubleKeyFrame KeyTime="0:0:1.6" Value="360"/>
15             </DoubleAnimationUsingKeyFrames>
16             <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="minCircle">
17                 <EasingDoubleKeyFrame KeyTime="0:0:1.6" Value="360"/>
18             </DoubleAnimationUsingKeyFrames>
19         </Storyboard>
20         <Storyboard x:Key="FillStoryboard" Completed="Storyboard_Completed">
21             <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(ed:Arc.EndAngle)" Storyboard.TargetName="FillArea">
22                 <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
23                 <EasingDoubleKeyFrame KeyTime="0:0:0.05" Value="0"/>
24             </DoubleAnimationUsingKeyFrames>
25             <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="FillArea">
26                 <EasingColorKeyFrame KeyTime="0:0:0" Value="#FFFF0000"/>
27                 <EasingColorKeyFrame KeyTime="0:0:0.05" Value="#FF008000"/>
28             </ColorAnimationUsingKeyFrames>
29         </Storyboard>
30     </UserControl.Resources>
31     <Viewbox>
32     <Grid>
33             <Border Name="MaxCircle" CornerRadius="500" Width="100" Height="100" Background="White"  Opacity="0.2"/>
34             <Border Name="minCircle" CornerRadius="500" Width="80" Height="80" BorderBrush="black" BorderThickness="2" Opacity="0.4" RenderTransformOrigin="0.5,0.5">
35                 <Border.RenderTransform>
36                     <TransformGroup>
37                         <ScaleTransform/>
38                         <SkewTransform/>
39                         <RotateTransform/>
40                         <TranslateTransform/>
41                     </TransformGroup>
42                 </Border.RenderTransform>
43                 <Border.Background>
44                     <LinearGradientBrush EndPoint="0.5,0" StartPoint="0.5,1">
45                         <GradientStop Color="White" Offset="0"/>
46                         <GradientStop Color="Transparent" Offset="0.5"/>
47                         <GradientStop Color="White" Offset="1"/>
48                     </LinearGradientBrush>
49                 </Border.Background>
50             </Border>
51             <ed:Arc Name="FillArea" ArcThickness="0.18" ArcThicknessUnit="Percent" StartAngle="0" EndAngle="0" Width="95" Height="95" Stretch="None" Opacity="0.8" Fill="Red"/>
52             <Label Name="ShowLabel" Width="60" Height="60" FontFamily="宋体" FontWeight="Bold" Content="{Binding ElementName=FillArea,Path=EndAngle,Converter={StaticResource converter}}" FontSize="32" Foreground="White" Opacity="0.8" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" />
53     </Grid>
54     </Viewbox>
55 </UserControl>
前端XMAL
WPF利用动画实现圆形进度条WPF利用动画实现圆形进度条
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Windows;
  6 using System.Windows.Controls;
  7 using System.Windows.Data;
  8 using System.Windows.Documents;
  9 using System.Windows.Input;
 10 using System.Windows.Media;
 11 using System.Windows.Media.Animation;
 12 using System.Windows.Media.Imaging;
 13 using System.Windows.Navigation;
 14 using System.Windows.Shapes;
 15 
 16 namespace MyUserControlLibrary
 17 {
 18     /// <summary>
 19     /// WaitingAndProgress.xaml 的交互逻辑
 20     /// </summary>
 21     public partial class WaitingAndProgress : UserControl
 22     {
 23         #region 属性
 24 
 25         private WaitAndProgressType showType = WaitAndProgressType.WaitingAndProgress;
 26         /// <summary>
 27         /// 当前样式类型
 28         /// </summary>
 29         [System.ComponentModel.Browsable(true),System.ComponentModel.Category("Appreance"),System.ComponentModel.Description("设置或获取当前样式类型")]
 30         public WaitAndProgressType ShowType {
 31             get {
 32                 return showType;
 33             }
 34             set {
 35                 showType = value;
 36             }
 37         }
 38 
 39         #endregion
 40 
 41         public WaitingAndProgress()
 42         {
 43             InitializeComponent();
 44         }
 45 
 46         #region 方法
 47 
 48         public void setPrecent(double d) {
 49             if (showType == WaitAndProgressType.Waiting) {
 50                 return;
 51             }
 52             Storyboard b = (Storyboard)this.Resources["FillStoryboard"];
 53             DoubleAnimationUsingKeyFrames df = (DoubleAnimationUsingKeyFrames)b.Children[0];
 54             ColorAnimationUsingKeyFrames cf = (ColorAnimationUsingKeyFrames)b.Children[1];
 55             if (d >= 0 && d <= 10)
 56             {
 57                 cf.KeyFrames[1].Value = ToColor("#FFFF3300");
 58             }
 59             if (d > 10 && d <= 20)
 60             {
 61                 cf.KeyFrames[1].Value = ToColor("#FFFF6600");
 62             }
 63             if (d > 20 && d <= 30)
 64             {
 65                 cf.KeyFrames[1].Value = ToColor("#FFFF9900");
 66             }
 67             if (d > 30 && d <= 40)
 68             {
 69                 cf.KeyFrames[1].Value = ToColor("#FFFFCC00");
 70             }
 71             if (d > 40 && d <= 50)
 72             {
 73                 cf.KeyFrames[1].Value = ToColor("#FFFFFF00");
 74             }
 75             if (d > 50 && d <= 60)
 76             {
 77                 cf.KeyFrames[1].Value = ToColor("#FFCCFF00");
 78             }
 79             if (d > 60 && d <= 70)
 80             {
 81                 cf.KeyFrames[1].Value = ToColor("#FF99FF00");
 82             }
 83             if (d > 70 && d <= 80)
 84             {
 85                 cf.KeyFrames[1].Value = ToColor("#FF66FF00");
 86             }
 87             if (d > 80 && d <= 90)
 88             {
 89                 cf.KeyFrames[1].Value = ToColor("#FF33FF00");
 90             }
 91             if (d > 90 && d <= 100)
 92             {
 93                 cf.KeyFrames[1].Value = ToColor("#FF00FF00");
 94             }
 95             df.KeyFrames[1].Value = d*3.6;
 96             b.Begin();
 97         }
 98 
 99         /// <summary>
100         /// 将blend的8位颜色值转为color
101         /// </summary>
102         /// <param name="colorName"></param>
103         /// <returns></returns>
104         public Color ToColor(string colorName)
105         {
106             if (colorName.StartsWith("#"))
107                 colorName = colorName.Replace("#", string.Empty);
108             int v = int.Parse(colorName, System.Globalization.NumberStyles.HexNumber);
109             return new Color()
110             {
111                 A = Convert.ToByte((v >> 24) & 255),
112                 R = Convert.ToByte((v >> 16) & 255),
113                 G = Convert.ToByte((v >> 8) & 255),
114                 B = Convert.ToByte((v >> 0) & 255)
115             };
116         }
117 
118         #endregion
119 
120         #region 事件
121 
122         //载入时事件处理
123         private void UserControl_Loaded(object sender, RoutedEventArgs e)
124         {
125             if (showType != WaitAndProgressType.Progress)
126             {
127                 Storyboard b1 = (Storyboard)this.Resources["MainStoryboard"];
128                 b1.Begin();
129                 if (showType == WaitAndProgressType.Waiting)
130                 {
131                     ShowLabel.Visibility = System.Windows.Visibility.Hidden;
132                 }
133                 else {
134                     ShowLabel.Visibility = System.Windows.Visibility.Visible;
135                 }
136             }
137             else {
138                 Storyboard b1 = (Storyboard)this.Resources["MainStoryboard"];
139                 b1.Stop();
140                 ShowLabel.Visibility = System.Windows.Visibility.Visible;
141             }
142         }
143 
144         //渐变动画完成时
145         private void Storyboard_Completed(object sender, EventArgs e)
146         {
147             Storyboard b = (Storyboard)this.Resources["FillStoryboard"];
148             ColorAnimationUsingKeyFrames cf = (ColorAnimationUsingKeyFrames)b.Children[1];
149             DoubleAnimationUsingKeyFrames df = (DoubleAnimationUsingKeyFrames)b.Children[0];
150             df.KeyFrames[0].Value = df.KeyFrames[1].Value;
151             cf.KeyFrames[0].Value = cf.KeyFrames[1].Value;
152         }
153 
154         #endregion
155 
156         
157     }
158 }
后台代码
WPF利用动画实现圆形进度条WPF利用动画实现圆形进度条
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Globalization;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Windows.Data;
 7 
 8 namespace MyUserControlLibrary
 9 {
10     /// <summary>
11     /// 将角度转化成百分比
12     /// </summary>
13     public class ConverterCircleToPercent:IValueConverter
14     {
15         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
16         {
17             return (int)(double.Parse(value.ToString()) * 10 / 36);
18         }
19         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
20         {
21             throw new NullReferenceException();
22         }
23     }
24 }
转换类型

 

上一篇:第 3 章 Systems architecture(系统架构)


下一篇:杀毒进入 “云安全”时代