hello world

wpf 水波进度条 用户控件

之前看公司web前端做了个 圆形的水波纹 进度条,就想用wpf 做一个,奈何自己太菜 一直做不出来,在看过 “普通的地球人” 的 “

WPF实现三星手机充电界面 博客之后 我也来照葫芦画个瓢。

废话不多说 先贴一下效果图

虽然样子 low 了些 但是基本满足我的需求了,下面是代码

前端

<UserControl x:Class="WaveProgress.UserControl.WaveProgressControl"
             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:local="clr-namespace:WaveProgress.UserControl"
             mc:Ignorable="d" 
             Height="150" Width="150" x:Name="wave_control">
    <UserControl.Resources>
        <Storyboard x:Key="WaterStoryboard">
            <PointAnimation Storyboard.TargetName="bs_Water" DesiredFrameRate="20" Storyboard.TargetProperty="Point1" From="90,60" To="90,90" Duration="00:00:2" AutoReverse="True" RepeatBehavior="Forever"></PointAnimation>
            <PointAnimation Storyboard.TargetName="bs_Water" DesiredFrameRate="20" Storyboard.TargetProperty="Point2" From="100,110" To="100,95" Duration="00:00:1.8" AutoReverse="True" RepeatBehavior="Forever"></PointAnimation>
        </Storyboard>
    </UserControl.Resources>
    <Grid Width="{Binding ElementName=wave_control,Path=Width}" Height="{Binding ElementName=wave_control,Path=Height}" 
          Background="{Binding WaveProgressBackground,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
        <Grid.Clip>
            <EllipseGeometry Center="75,75" RadiusX="75" RadiusY="75" ></EllipseGeometry>
        </Grid.Clip>
        <StackPanel Width="150" VerticalAlignment="Bottom">
            <Path Fill="{Binding WavePorgressBarColor,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" >
                <Path.Data>
                    <PathGeometry FillRule="EvenOdd" >
                        <PathFigure StartPoint="0,90" >
                            <BezierSegment x:Name="bs_Water" Point1="90,60" Point2="100,110" Point3="150,90"></BezierSegment>
                            <PolyLineSegment Points="150,100 0,100"></PolyLineSegment>
                        </PathFigure>
                    </PathGeometry>
                </Path.Data>
                <Path.Triggers>
                    <EventTrigger RoutedEvent="Path.Loaded">
                        <BeginStoryboard Storyboard="{StaticResource WaterStoryboard}"></BeginStoryboard>
                    </EventTrigger>
                </Path.Triggers>
            </Path>
            <Rectangle Height="{Binding WaveProgressHeight,UpdateSourceTrigger=PropertyChanged}" Fill="{Binding WavePorgressBarColor,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
        </StackPanel>
        <Ellipse VerticalAlignment="Bottom" Width="150" Height="150" Stroke="{Binding WaveBorderBrush,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Fill="Transparent" 
                 StrokeThickness="{Binding WaveBorderThickness,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="22" Foreground="{Binding TextColor,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
            <Run Text="{Binding DisPlayValue,UpdateSourceTrigger=PropertyChanged}"></Run>
            <Run Text="%"></Run>
        </TextBlock>
    </Grid>
</UserControl>

后台

using System.Globalization;
using System.Windows;
using System.Windows.Media;

namespace WaveProgress.UserControl
{
    /// <summary>
    /// WaveProgressControl.xaml 的交互逻辑
    /// </summary>
    public partial class WaveProgressControl : System.Windows.Controls.UserControl
    {
        public WaveProgressControl()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        public static readonly DependencyProperty WaveProgressBackgroundProperty = DependencyProperty.Register(
            "WaveProgressBackground", typeof(SolidColorBrush), typeof(WaveProgressControl), new PropertyMetadata(Brushes.White));

        /// <summary>
        /// 进度条背景色
        /// </summary>
        public SolidColorBrush WaveProgressBackground
        {
            get { return (SolidColorBrush) GetValue(WaveProgressBackgroundProperty); }
            set { SetValue(WaveProgressBackgroundProperty, value); }
        }

        public static readonly DependencyProperty WaveBorderBrushProperty = DependencyProperty.Register(
            "WaveBorderBrush", typeof(SolidColorBrush), typeof(WaveProgressControl), new PropertyMetadata(Brushes.Blue));
        /// <summary>
        /// 边框颜色
        /// </summary>
        public SolidColorBrush WaveBorderBrush
        {
            get { return (SolidColorBrush) GetValue(WaveBorderBrushProperty); }
            set { SetValue(WaveBorderBrushProperty, value); }
        }

        public static readonly DependencyProperty WaveBorderThicknessProperty = DependencyProperty.Register(
            "WaveBorderThickness", typeof(double), typeof(WaveProgressControl), new PropertyMetadata(2.0));

        /// <summary>
        /// 边框粗细
        /// </summary>
        public double WaveBorderThickness
        {
            get { return (double) GetValue(WaveBorderThicknessProperty); }
            set { SetValue(WaveBorderThicknessProperty, value); }
        }

     
        public static readonly DependencyProperty WavePorgressBarColorProperty = DependencyProperty.Register(
            "WavePorgressBarColor", typeof(SolidColorBrush), typeof(WaveProgressControl), new PropertyMetadata(Brushes.Red));
        /// <summary>
        /// 进度条颜色
        /// </summary>
        public SolidColorBrush WavePorgressBarColor
        {
            get { return (SolidColorBrush) GetValue(WavePorgressBarColorProperty); }
            set { SetValue(WavePorgressBarColorProperty, value); }
        }

        public static readonly DependencyProperty TextColorProperty = DependencyProperty.Register(
            "TextColor", typeof(SolidColorBrush), typeof(WaveProgressControl), new PropertyMetadata(Brushes.Black));
        /// <summary>
        /// 文字颜色
        /// </summary>
        public SolidColorBrush TextColor
        {
            get { return (SolidColorBrush) GetValue(TextColorProperty); }
            set { SetValue(TextColorProperty, value); }
        }

        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
            "Value", typeof(double), typeof(WaveProgressControl), new PropertyMetadata(default(double)));

        /// <summary>
        /// 当前进度
        /// </summary>
        public double Value
        {
            get { return (double) GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register(
            "MaxValue", typeof(double), typeof(WaveProgressControl), new PropertyMetadata(default(double)));

        public double MaxValue
        {
            get { return (double) GetValue(MaxValueProperty); }
            set { SetValue(MaxValueProperty, value); }
        }

        public static readonly DependencyProperty DisPlayValueProperty = DependencyProperty.Register(
            "DisPlayValue", typeof(string), typeof(WaveProgressControl), new PropertyMetadata("0"));

        public string DisPlayValue
        {
            get { return (string) GetValue(DisPlayValueProperty); }
            set { SetValue(DisPlayValueProperty, value); }
        }

        public static readonly DependencyProperty WaveProgressHeightProperty = DependencyProperty.Register(
            "WaveProgressHeight", typeof(double), typeof(WaveProgressControl), new PropertyMetadata(default(double)));

        /// <summary>
        /// 次属性不要手动设置
        /// </summary>
        public double WaveProgressHeight
        {
            get { return (double) GetValue(WaveProgressHeightProperty); }
            set { SetValue(WaveProgressHeightProperty, value); }
        }

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            if (e.Property == ValueProperty)
            {
                double bl = Value / MaxValue;
                WaveProgressHeight = 140 * bl;
                DisPlayValue = (bl * 100).ToString(CultureInfo.InvariantCulture);
            }
        }
    }

}

 

美中不足的是:

1、大小是我写死了的,因为里面那个水波是用path 写的 是个固定的

2、仔细看 中间有条白色的线(等有时间在解决吧)

 

学习到的知识:

1、学会用贝塞尔曲线,和它的动画

2、学会了Clip剪裁

3、看大佬的文章果然受益匪浅

 

附:解决有一条白线的问题

将水波纹进度条的 边线设置为0,代码为:

<Path SnapsToDevicePixels="True" 
                  Fill="{Binding WavePorgressBarColor,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 
                  Stroke="{Binding WavePorgressBarColor,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 
                  StrokeThickness="0">
                <Path.Data>
                    <PathGeometry FillRule="EvenOdd" >
                        <PathFigure StartPoint="0,90" >
                            <BezierSegment x:Name="bs_Water" Point1="90,60" Point2="100,110" Point3="150,90"></BezierSegment>
                            <PolyLineSegment Points="150,100 0,100"></PolyLineSegment>
                        </PathFigure>
                    </PathGeometry>
                </Path.Data>
                <Path.Triggers>
                    <EventTrigger RoutedEvent="Path.Loaded">
                        <BeginStoryboard Storyboard="{StaticResource WaterStoryboard}"></BeginStoryboard>
                    </EventTrigger>
                </Path.Triggers>
            </Path>
            <Rectangle SnapsToDevicePixels="True" Height="{Binding WaveProgressHeight,UpdateSourceTrigger=PropertyChanged}" Fill="{Binding WavePorgressBarColor,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>

 

将此代码直接覆盖 原有代码即可(StackPanel 中的那两个控件)

附源码:https://github.com/t115liyanpeng/WaveProgress

posted @ 2019-03-05 18:05  我是刹那、  阅读(2753)  评论(6编辑  收藏  举报