基于C#/Winform实现的Win8MetroLoading动画
非常喜欢Metro风格的界面,所以想模仿一下一些UI效果的实现,网上找到了很多,但都是CSS3,WPF等实现,对于XAML和CSS3一窍不通,无奈下只有自己开始写。
下面是源码:
- 1 using System;
- 2 using System.ComponentModel;
- 3 using System.Drawing;
- 4 using System.Drawing.Drawing2D;
- 5 using System.Linq;
- 6 using System.Threading;
- 7 using System.Windows.Forms;
- 8 using ThreadingTimer = System.Threading.Timer;
- 9 using UITimer = System.Windows.Forms.Timer;
- 10
- 11 namespace LoadingCircle
- 12 {
- 13 /// <summary>
- 14 /// 表示一个加载圆圈动画
- 15 /// </summary>
- 16 [ToolboxBitmap(typeof (LoadingCircle), "LoadingCircleIcon.png")]
- 17 public partial class LoadingCircle : UserControl
- 18 {
- 19 #region 构造
- 20
- 21 public LoadingCircle()
- 22 {
- 23 InitializeComponent();
- 24
- 25 //双缓冲,禁擦背景
- 26 SetStyle(
- 27 ControlStyles.AllPaintingInWmPaint |
- 28 ControlStyles.UserPaint |
- 29 ControlStyles.OptimizedDoubleBuffer,
- 30 true);
- 31
- 32 //初始化绘图timer
- 33 _graphicsTmr = new UITimer {Interval = 1};
- 34 //Invalidate()强制重绘,绘图操作在OnPaint中实现
- 35 _graphicsTmr.Tick += (sender1, e1) => Invalidate(false);
- 36
- 37 _dotSize = Width/10f;
- 38
- 39 //初始化"点"
- 40 _dots = new Dot[5];
- 41
- 42 Color = Color.White;
- 43 }
- 44
- 45 #endregion 构造
- 46
- 47 #region 属性
- 48
- 49 /// <summary>
- 50 /// 圆心
- 51 /// </summary>
- 52 [Browsable(false)]
- 53 public PointF CircleCenter
- 54 {
- 55 get { return new PointF(Width/2f, Height/2f); }
- 56 }
- 57
- 58 /// <summary>
- 59 /// 半径
- 60 /// </summary>
- 61 [Browsable(false)]
- 62 public float CircleRadius
- 63 {
- 64 get { return Width/2f - _dotSize; }
- 65 }
- 66
- 67 /// <summary>
- 68 /// 颜色
- 69 /// </summary>
- 70 [Browsable(true), Category("Appearance"), Description("设置\"点\"的前景色")]
- 71 public Color Color { get; set; }
- 72
- 73 #endregion 属性
- 74
- 75 #region 字段
- 76
- 77 //点数组
- 78 private readonly Dot[] _dots;
- 79
- 80 //Timers
- 81 private readonly UITimer _graphicsTmr;
- 82 private ThreadingTimer _actionTmr;
- 83
- 84 //点大小
- 85 private float _dotSize;
- 86
- 87 //是否活动
- 88 private bool _isActived;
- 89
- 90 //是否绘制:用于状态重置时挂起与恢复绘图
- 91 private bool _isDrawing = true;
- 92
- 93 //Timer计数:用于延迟启动每个点
- 94 private int _timerCount;
- 95
- 96 #endregion 字段
- 97
- 98 #region 常量
- 99
- 100 //动作间隔(Timer)
- 101 private const int ActionInterval = 30;
- 102
- 103 //计数基数:用于计算每个点启动延迟:index * timerCountRadix
- 104 private const int TimerCountRadix = 45;
- 105
- 106 #endregion 常量
- 107
- 108 #region 方法
- 109
- 110 //检查是否重置
- 111 private bool CheckToReset()
- 112 {
- 113 return _dots.Count(d => d.Opacity > 0) == 0;
- 114 }
- 115
- 116 //初始化点元素
- 117 private void CreateDots()
- 118 {
- 119 for (int i = 0; i < _dots.Length; ++i)
- 120 _dots[i] = new Dot(CircleCenter, CircleRadius);
- 121 }
- 122
- 123 /// <summary>
- 124 /// 开关
- 125 /// </summary>
- 126 public bool Switch()
- 127 {
- 128 if (!_isActived)
- 129 Start();
- 130 else
- 131 Stop();
- 132
- 133 return _isActived;
- 134 }
- 135
- 136 /// <summary>
- 137 /// 开始
- 138 /// </summary>
- 139 public void Start()
- 140 {
- 141 CreateDots();
- 142
- 143 _timerCount = 0;
- 144 foreach (Dot dot in _dots)
- 145 dot.Reset();
- 146
- 147 _graphicsTmr.Start();
- 148
- 149 //初始化动作timer
- 150 _actionTmr = new ThreadingTimer(
- 151 state =>
- 152 {
- 153 //动画动作
- 154 for (int i = 0; i < _dots.Length; i++)
- 155 if (_timerCount++ > i * TimerCountRadix)
- 156 _dots[i].DotAction();
- 157
- 158 //是否重置
- 159 if (CheckToReset())
- 160 {
- 161 //重置前暂停绘图
- 162 _isDrawing = false;
- 163
- 164 _timerCount = 0;
- 165
- 166 foreach (Dot dot in _dots)
- 167 dot.Reset();
- 168
- 169 //恢复绘图
- 170 _isDrawing = true;
- 171 }
- 172
- 173 _actionTmr.Change(ActionInterval, Timeout.Infinite);
- 174 },
- 175 null, ActionInterval, Timeout.Infinite);
- 176
- 177 _isActived = true;
- 178 }
- 179
- 180 /// <summary>
- 181 /// 停止
- 182 /// </summary>
- 183 public void Stop()
- 184 {
- 185 _graphicsTmr.Stop();
- 186 _actionTmr.Dispose();
- 187 _isActived = false;
- 188 }
- 189
- 190 #endregion 方法
- 191
- 192 #region 重写
- 193
- 194 protected override void OnPaint(PaintEventArgs e)
- 195 {
- 196 if (_isActived && _isDrawing)
- 197 {
- 198 //抗锯齿
- 199 e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
- 200
- 201 using (var bmp = new Bitmap(200, 200))
- 202 {
- 203 //缓冲绘制
- 204 using (Graphics bufferGraphics = Graphics.FromImage(bmp))
- 205 {
- 206 //抗锯齿
- 207 bufferGraphics.SmoothingMode = SmoothingMode.HighQuality;
- 208 foreach (Dot dot in _dots)
- 209 {
- 210 var rect = new RectangleF(
- 211 new PointF(dot.Location.X - _dotSize/2, dot.Location.Y - _dotSize/2),
- 212 new SizeF(_dotSize, _dotSize));
- 213
- 214 bufferGraphics.FillEllipse(new SolidBrush(Color.FromArgb(dot.Opacity, Color)),
- 215 rect);
- 216 }
- 217 }
- 218
- 219 //贴图
- 220 e.Graphics.DrawImage(bmp, new PointF(0, 0));
- 221 } //bmp disposed
- 222 }
- 223
- 224 base.OnPaint(e);
- 225 }
- 226
- 227 protected override void OnResize(EventArgs e)
- 228 {
- 229 Height = Width;
- 230 _dotSize = Width/12f;
- 231
- 232 base.OnResize(e);
- 233 }
- 234
- 235 #endregion 重写
- 236 }
- 237 }
LoadingCircle.cs
- 1 using System.Drawing;
- 2
- 3 namespace LoadingCircle
- 4 {
- 5 /// <summary>
- 6 /// 表示一个"点"
- 7 /// </summary>
- 8 internal sealed class Dot
- 9 {
- 10 #region 字段/属性
- 11
- 12 //圆心
- 13 private readonly PointF _circleCenter;
- 14 //半径
- 15 private readonly float _circleRadius;
- 16
- 17 /// <summary>
- 18 /// 当前帧绘图坐标,在每次DotAction()时重新计算
- 19 /// </summary>
- 20 public PointF Location;
- 21
- 22 //点相对于圆心的角度,用于计算点的绘图坐标
- 23 private int _angle;
- 24 //透明度
- 25 private int _opacity;
- 26 //动画进度
- 27 private int _progress;
- 28 //速度
- 29 private int _speed;
- 30
- 31 /// <summary>
- 32 /// 透明度
- 33 /// </summary>
- 34 public int Opacity
- 35 {
- 36 get { return _opacity < MinOpacity ? MinOpacity : (_opacity > MaxOpacity ? MaxOpacity : _opacity); }
- 37 }
- 38
- 39 #endregion
- 40
- 41 #region 常量
- 42
- 43 //最小/最大速度
- 44 private const int MinSpeed = 2;
- 45 private const int MaxSpeed = 11;
- 46
- 47 //出现区的相对角度
- 48 private const int AppearAngle = 90;
- 49 //减速区的相对角度
- 50 private const int SlowAngle = 225;
- 51 //加速区的相对角度
- 52 private const int QuickAngle = 315;
- 53
- 54 //最小/最大角度
- 55 private const int MinAngle = 0;
- 56 private const int MaxAngle = 360;
- 57
- 58 //淡出速度
- 59 private const int AlphaSub = 25;
- 60
- 61 //最小/最大透明度
- 62 private const int MinOpacity = 0;
- 63 private const int MaxOpacity = 255;
- 64
- 65 #endregion 常量
- 66
- 67 #region 构造器
- 68
- 69 public Dot(PointF circleCenter, float circleRadius)
- 70 {
- 71 Reset();
- 72 _circleCenter = circleCenter;
- 73 _circleRadius = circleRadius;
- 74 }
- 75
- 76 #endregion 构造器
- 77
- 78 #region 方法
- 79
- 80 /// <summary>
- 81 /// 重新计算当前帧绘图坐标
- 82 /// </summary>
- 83 private void ReCalcLocation()
- 84 {
- 85 Location = Common.GetDotLocationByAngle(_circleCenter, _circleRadius, _angle);
- 86 }
- 87
- 88 /// <summary>
- 89 /// 点动作
- 90 /// </summary>
- 91 public void DotAction()
- 92 {
- 93 switch (_progress)
- 94 {
- 95 case 0:
- 96 {
- 97 _opacity = MaxOpacity;
- 98 AddSpeed();
- 99 if (_angle + _speed >= SlowAngle && _angle + _speed < QuickAngle)
- 100 {
- 101 _progress = 1;
- 102 _angle = SlowAngle - _speed;
- 103 }
- 104 }
- 105 break;
- 106 case 1:
- 107 {
- 108 SubSpeed();
- 109 if (_angle + _speed >= QuickAngle || _angle + _speed < SlowAngle)
- 110 {
- 111 _progress = 2;
- 112 _angle = QuickAngle - _speed;
- 113 }
- 114 }
- 115 break;
- 116 case 2:
- 117 {
- 118 AddSpeed();
- 119 if (_angle + _speed >= SlowAngle && _angle + _speed < QuickAngle)
- 120 {
- 121 _progress = 3;
- 122 _angle = SlowAngle - _speed;
- 123 }
- 124 }
- 125 break;
- 126 case 3:
- 127 {
- 128 SubSpeed();
- 129 if (_angle + _speed >= QuickAngle && _angle + _speed < MaxAngle)
- 130 {
- 131 _progress = 4;
- 132 _angle = QuickAngle - _speed;
- 133 }
- 134 }
- 135 break;
- 136 case 4:
- 137 {
- 138 SubSpeed();
- 139 if (_angle + _speed >= MinAngle && _angle + _speed < AppearAngle)
- 140 {
- 141 _progress = 5;
- 142 _angle = MinAngle;
- 143 }
- 144 }
- 145 break;
- 146 case 5:
- 147 {
- 148 AddSpeed();
- 149 FadeOut();
- 150 }
- 151 break;
- 152 }
- 153
- 154 //移动
- 155 _angle = _angle >= (MaxAngle - _speed) ? MinAngle : _angle + _speed;
- 156 //重新计算坐标
- 157 ReCalcLocation();
- 158 }
- 159
- 160 //淡出
- 161 private void FadeOut()
- 162 {
- 163 if ((_opacity -= AlphaSub) <= 0)
- 164 _angle = AppearAngle;
- 165 }
- 166
- 167 //重置状态
- 168 public void Reset()
- 169 {
- 170 _angle = AppearAngle;
- 171 _speed = MinSpeed;
- 172 _progress = 0;
- 173 _opacity = 1;
- 174 }
- 175
- 176 //加速
- 177 private void AddSpeed()
- 178 {
- 179 if (++_speed >= MaxSpeed) _speed = MaxSpeed;
- 180 }
- 181
- 182 //减速
- 183 private void SubSpeed()
- 184 {
- 185 if (--_speed <= MinSpeed) _speed = MinSpeed;
- 186 }
- 187
- 188 #endregion 方法
- 189 }
- 190 }
Dot.cs
- 1 using System;
- 2 using System.Drawing;
- 3
- 4 namespace LoadingCircle
- 5 {
- 6 public static class Common
- 7 {
- 8 /// <summary>
- 9 /// 根据半径、角度求圆上坐标
- 10 /// </summary>
- 11 /// <param name="center">圆心</param>
- 12 /// <param name="radius">半径</param>
- 13 /// <param name="angle">角度</param>
- 14 /// <returns>坐标</returns>
- 15 public static PointF GetDotLocationByAngle(PointF center, float radius, int angle)
- 16 {
- 17 var x = (float) (center.X + radius*Math.Cos(angle*Math.PI/180));
- 18 var y = (float) (center.Y + radius*Math.Sin(angle*Math.PI/180));
- 19
- 20 return new PointF(x, y);
- 21 }
- 22 }
- 23 }
Common.cs
附Demo链接,含控件源码:http://download.csdn.net/detail/coffee_mx/7510695
PS:有些地方肯定还有一些不协调,没办法,笔者审美有限,请大家通过代码内常量进行微调。欢迎大神们指点……
基于C#/Winform实现的Win8MetroLoading动画的更多相关文章
- 基于 SailingEase WinForm Framework 开发客户端程序(3:实现菜单/工具栏按钮的解耦及状态控制)
本系列文章将详细阐述客户端应用程序的设计理念,实现方法. 本系列文章以 SailingEase WinForm Framework 为基础进行设计并实现,但其中的设计理念及方法,亦适用于任何类型的客 ...
- 基于 SailingEase WinForm Framework 开发优秀的客户端应用程序(目录)
本系统文章将详细阐述客户端应用程序的设计理念,实现方法. 本系列文章以 SailingEase WinForm Framework 为基础进行设计并实现,但其中的设计理念及方法,亦适用于任何类型的客 ...
- 基于 SailingEase WinForm Framework 开发优秀的客户端应用程序(1:概述)
本系统文章将详细阐述客户端应用程序的设计理念,实现方法. 本系列文章以 SailingEase WinForm Framework 为基础进行设计并实现,但其中的设计理念及方法,亦适用于任何类型的客 ...
- 基于jQuery点击加载动画按钮特效
分享一款基于jQuery点击加载动画按钮特效.这是一款基于jQuery+CSS3实现的鼠标点击按钮加载动画特效代码.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div ...
- 基于html5页面滚动背景图片动画效果
基于html5页面滚动背景图片动画效果是一款带索引按钮的页面滚动动画特效代码.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div id="fullpage&q ...
- 基于CSS3制作的鼠标悬停动画菜单
之前分享了好多款css3实现的鼠标悬停效果.今天再给大家带来一款基于CSS3制作的鼠标悬停动画菜单.这款菜单适用浏览器:360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界 ...
- 基于jQuery弹出层图片动画查看代码
分享一款基于jQuery弹出层图片动画查看代码是一款鼠标单击文字或图片内容放大显示且含圆角投影效果.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div class=&q ...
- 基于jQuery CSS3鼠标点击动画效果
分享基于jQuery CSS3鼠标点击动画效果支持图片或内容滑动,允许设置动画延迟效果.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div class="co ...
- 30款基于 jQuery & CSS3 的加载动画和进度条插件
我们所生活每一天看到的新技术或新设计潮流的兴起,Web 开发正处在上升的时代.HTML5 & CSS3 技术的发展让 Web 端可以实现的功能越来越强大. 加载动画和进度条使网站更具吸引力.该 ...
随机推荐
- RMI之由浅入深(一)
0x01.什么是RMI RMI(Remote Method Invocation)即Java远程方法调用,RMI用于构建分布式应用程序,RMI实现了Java程序之间跨JVM的远程通信.顾名思义,远程方 ...
- mac强制关闭应用
原文链接http://zhhll.icu/2020/08/13/Mac/%E5%BC%BA%E5%88%B6%E7%BB%88%E6%AD%A2%E5%BA%94%E7%94%A8/ 有时候使用Mac ...
- spring boot 邮件服务
引入依赖 添加spring-boot-starter-mail包引用 <dependency> <groupId>org.springframework.boot</gr ...
- NodeJS各个平台安装详细
http://www.runoob.com/nodejs/nodejs-install-setup.html 记录
- Unity优化 1
浅谈Unity中的GC以及优化(转) Unity 官方文档,正巧在博客园发现了已经有位大神(zblade)把原文翻译出来了,而且质量很高~,译文地址 在这里.下面我就可耻地把译文搬运了过来,作为上面思 ...
- 【JDBC核心】JDBC 概述
JDBC 概述 数据的持久化 持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用.大多数情况下,特别是企业级应用,数据持久化意味着将内存中的数据保存到硬盘上加以"固 ...
- 十五:SQL注入之oracle,Mangodb注入
Access,Mysql,mssql,mangoDB,postgresql,sqlite,oracle,sybase JSON类型的数据注入: 键名:键值 {"a":"1 ...
- 安装jdk-windows系统
1. 明确需要安装的jdk版本,注意jdk存在小版本号,例如jdk1.7_51,如果不清楚小版本号的话建议安装最新版本的jdk: 2. 打开cmd命令窗口,输入java -version查看本机是否安 ...
- expect的使用
1. expect概述 1.1 expect的功能 脚本执行时,有时会需要人工进行交互输入,这时可以通过expect工具来实现自动交互. expect是一种shell解释器,但是expect可以在命令 ...
- CSS实现迷你键盘
最近做了一个迷你键盘的dome,这里分享给大家 dome下载地址(点击下载) 代码如下: <!DOCTYPE html> <html lang="en" > ...