基于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 端可以实现的功能越来越强大. 加载动画和进度条使网站更具吸引力.该 ...
随机推荐
- 史上最全的pycharm快捷键!快进来点个收藏吧
Alt+Enter 自动添加包 Ctrl+t SVN更新 Ctrl+k SVN提交 [编辑类:](https://link.zhihu.com/?target=https://www.jianshu. ...
- Modbus 仿真测试工具 Mod_Rssim 详细图文教程
Mod_RSsim是一款轻量级的Modbus从机模拟器,它可以模拟ModBusTCP和ModBusRTU的从机,能够同时模拟254个被控站,软件使用简单方便,可以满足一般的主机调试. 官方网站:www ...
- NP问题/NP完全问题(NP-complete problem)如何判断是否是NP完全问题
在算法复杂度分析的过程中,人们常常用特定的函数来描述目标算法,随着变量n的增长,时间或者空间消耗的增长曲线,近而进一步分析算法的可行性(有效性). 引入了Big-O,Big-Ω,来描述目标算法的上限. ...
- js原型链原理
先附上原型链的图,能看懂的本文就没必要看了,看不懂的可以带着疑问看文章 一.构造函数 什么是构造函数:当一个普通函数创建一个类对象是,那么就程它为构造函数. 特点: 默认首字母大写 使用new关键字来 ...
- 【JDBC核心】批量插入
批量插入 批量执行 SQL 语句 当需要成批插入或者更新记录时,可以采用 Java 的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理.通常情况下比单独提交处理更有效率. JDBC 的批量 ...
- 【C++】《Effective C++》第七章
第七章 模板与泛型编程 条款41:了解隐式接口和编译期多态 面向对象设计中的类(class)考虑的是显式接口(explict interface)和运行时多态,而模板编程中的模板(template)考 ...
- ssh连接不上vmware虚拟机centos7.5
在vmware中安装centos7.5后,手动设置IP地址192.168.1.5,发现主机ping不通虚拟机的IP,以下是我的解决办法 1.vmware设置选择仅主机模式 2.在主机查看vmnet1( ...
- 日常采坑:.NetCore上传大文件
一..NetCore上传大文件 .NetCore3.1 webapi 本地测试上传时,遇到一个坑,大点的文件直接失败,根本不走控制器方法. 二.大文件上传配置 IFormFile方式,vs IIS E ...
- (十三)利用BASE_DIR来import模板
实际工程的组织架构一般是这样的: bin包下的bin.py是实际的执行文件,my_mould包下的是业务逻辑的实现模板 bin.py需要import my_mould下的py文件,而bin和my_mo ...
- 【Linux】make编译的小技巧
------------------------------------------------------------------------------------------------- | ...