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

2023-02-13,,,,

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

  这是我的第一篇随笔,最近因为工作需要,开始学习WPF相关技术,自己想实现以下圆形进度条的效果,逛了园子发现基本都是很久以前的文章,实现方式一般都是GDI实现的,想到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将整个效果框起来,这样以后无论你怎么拖拽这个空间,内部都不会出现变形的效果了。

代码如下:

 <UserControl x:Class="MyUserControlLibrary.WaitingAndProgress"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
xmlns:local ="clr-namespace:MyUserControlLibrary"
mc:Ignorable="d"
d:DesignHeight="" d:DesignWidth="" Loaded="UserControl_Loaded">
<UserControl.Resources>
<local:ConverterCircleToPercent x:Key="converter"/>
<Storyboard x:Key="MainStoryboard" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="ShowArea">
<EasingDoubleKeyFrame KeyTime="0:0:1.6" Value=""/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="minCircle">
<EasingDoubleKeyFrame KeyTime="0:0:1.6" Value=""/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="FillStoryboard" Completed="Storyboard_Completed">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(ed:Arc.EndAngle)" Storyboard.TargetName="FillArea">
<EasingDoubleKeyFrame KeyTime="" Value=""/>
<EasingDoubleKeyFrame KeyTime="0:0:0.05" Value=""/>
</DoubleAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="FillArea">
<EasingColorKeyFrame KeyTime="0:0:0" Value="#FFFF0000"/>
<EasingColorKeyFrame KeyTime="0:0:0.05" Value="#FF008000"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<Viewbox>
<Grid>
<Border Name="MaxCircle" CornerRadius="" Width="" Height="" Background="White" Opacity="0.2"/>
<Border Name="minCircle" CornerRadius="" Width="" Height="" BorderBrush="black" BorderThickness="" Opacity="0.4" RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Border.RenderTransform>
<Border.Background>
<LinearGradientBrush EndPoint="0.5,0" StartPoint="0.5,1">
<GradientStop Color="White" Offset=""/>
<GradientStop Color="Transparent" Offset="0.5"/>
<GradientStop Color="White" Offset=""/>
</LinearGradientBrush>
</Border.Background>
</Border>
<ed:Arc Name="FillArea" ArcThickness="0.18" ArcThicknessUnit="Percent" StartAngle="" EndAngle="" Width="" Height="" Stretch="None" Opacity="0.8" Fill="Red"/>
<Label Name="ShowLabel" Width="" Height="" FontFamily="宋体" FontWeight="Bold" Content="{Binding ElementName=FillArea,Path=EndAngle,Converter={StaticResource converter}}" FontSize="" Foreground="White" Opacity="0.8" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" />
</Grid>
</Viewbox>
</UserControl>

前端XMAL

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes; namespace MyUserControlLibrary
{
/// <summary>
/// WaitingAndProgress.xaml 的交互逻辑
/// </summary>
public partial class WaitingAndProgress : UserControl
{
#region 属性 private WaitAndProgressType showType = WaitAndProgressType.WaitingAndProgress;
/// <summary>
/// 当前样式类型
/// </summary>
[System.ComponentModel.Browsable(true),System.ComponentModel.Category("Appreance"),System.ComponentModel.Description("设置或获取当前样式类型")]
public WaitAndProgressType ShowType {
get {
return showType;
}
set {
showType = value;
}
} #endregion public WaitingAndProgress()
{
InitializeComponent();
} #region 方法 public void setPrecent(double d) {
if (showType == WaitAndProgressType.Waiting) {
return;
}
Storyboard b = (Storyboard)this.Resources["FillStoryboard"];
DoubleAnimationUsingKeyFrames df = (DoubleAnimationUsingKeyFrames)b.Children[];
ColorAnimationUsingKeyFrames cf = (ColorAnimationUsingKeyFrames)b.Children[];
if (d >= && d <= )
{
cf.KeyFrames[].Value = ToColor("#FFFF3300");
}
if (d > && d <= )
{
cf.KeyFrames[].Value = ToColor("#FFFF6600");
}
if (d > && d <= )
{
cf.KeyFrames[].Value = ToColor("#FFFF9900");
}
if (d > && d <= )
{
cf.KeyFrames[].Value = ToColor("#FFFFCC00");
}
if (d > && d <= )
{
cf.KeyFrames[].Value = ToColor("#FFFFFF00");
}
if (d > && d <= )
{
cf.KeyFrames[].Value = ToColor("#FFCCFF00");
}
if (d > && d <= )
{
cf.KeyFrames[].Value = ToColor("#FF99FF00");
}
if (d > && d <= )
{
cf.KeyFrames[].Value = ToColor("#FF66FF00");
}
if (d > && d <= )
{
cf.KeyFrames[].Value = ToColor("#FF33FF00");
}
if (d > && d <= )
{
cf.KeyFrames[].Value = ToColor("#FF00FF00");
}
df.KeyFrames[].Value = d*3.6;
b.Begin();
} /// <summary>
/// 将blend的8位颜色值转为color
/// </summary>
/// <param name="colorName"></param>
/// <returns></returns>
public Color ToColor(string colorName)
{
if (colorName.StartsWith("#"))
colorName = colorName.Replace("#", string.Empty);
int v = int.Parse(colorName, System.Globalization.NumberStyles.HexNumber);
return new Color()
{
A = Convert.ToByte((v >> ) & ),
R = Convert.ToByte((v >> ) & ),
G = Convert.ToByte((v >> ) & ),
B = Convert.ToByte((v >> ) & )
};
} #endregion #region 事件 //载入时事件处理
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
if (showType != WaitAndProgressType.Progress)
{
Storyboard b1 = (Storyboard)this.Resources["MainStoryboard"];
b1.Begin();
if (showType == WaitAndProgressType.Waiting)
{
ShowLabel.Visibility = System.Windows.Visibility.Hidden;
}
else {
ShowLabel.Visibility = System.Windows.Visibility.Visible;
}
}
else {
Storyboard b1 = (Storyboard)this.Resources["MainStoryboard"];
b1.Stop();
ShowLabel.Visibility = System.Windows.Visibility.Visible;
}
} //渐变动画完成时
private void Storyboard_Completed(object sender, EventArgs e)
{
Storyboard b = (Storyboard)this.Resources["FillStoryboard"];
ColorAnimationUsingKeyFrames cf = (ColorAnimationUsingKeyFrames)b.Children[];
DoubleAnimationUsingKeyFrames df = (DoubleAnimationUsingKeyFrames)b.Children[];
df.KeyFrames[].Value = df.KeyFrames[].Value;
cf.KeyFrames[].Value = cf.KeyFrames[].Value;
} #endregion }
}

后台代码

 using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows.Data; namespace MyUserControlLibrary
{
/// <summary>
/// 将角度转化成百分比
/// </summary>
public class ConverterCircleToPercent:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)(double.Parse(value.ToString()) * / );
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NullReferenceException();
}
}
}

转换类型

WPF利用动画实现圆形进度条的相关教程结束。

《WPF利用动画实现圆形进度条.doc》

下载本文的Word格式文档,以方便收藏与打印。