基于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 端可以实现的功能越来越强大. 加载动画和进度条使网站更具吸引力.该 ...
随机推荐
- Spring(1) --入门(IoC,AOP)
说说你对spring的理解? Spring框架是一个轻量级的企业级开发的一站式解决方案,所谓一站式解决方案就是可以基于Spring解决Java EE开发的所有问题.Spring框架主要提供了IoC容器 ...
- 对数几率回归(逻辑回归)原理与Python实现
目录 一.对数几率和对数几率回归 二.Sigmoid函数 三.极大似然法 四.梯度下降法 四.Python实现 一.对数几率和对数几率回归 在对数几率回归中,我们将样本的模型输出\(y^*\)定义 ...
- EasyUI 表单插件 multiline easyui-textbox 多行换行失效问题
1.问题描述:原始html: <input class="easyui-textbox" name="myname" id="myid" ...
- 学习记录——使用PHP实现数据增删查改等基本功能(前后端分离)
萌新初次学习服务器端语言,分享学习经验 实现功能:1.显示数据表 2.对数据进行分页 3.对数据进行增删查改 由于本萌新采用前后端完全分离方案,所以数据传输用的ajax,为了提高代码的复用 ...
- Mac M1原生(ARM64)Golang dev&debug
前言 通过本文最终实现了在M1芯片的Mac mini上的Goland的开发,并通过编译源码解决了无法DEBUG的问题. Go 1.16版将正式支持Apple Silicon M1芯片,即arm64架构 ...
- 浅谈TypeScript,配置文件以及数据类型
TypeScript在javaScript基础上多了一些拓展特性,多出来的是一些类型系统以及对ES6新特性的支持最终会编译成原始的javaScript, 文件名以.ts结尾,编译过后.js结尾,在an ...
- C++ 中的 inline 详解
inline:是一个关键词,放在一个函数前面,说明这个函数是inline函数. inline函数是什么?inline有什么作用? 为了解答这个问题,我们首先要知道编译器是如何为我们工作的. 先看一段代 ...
- Java开发手册之工程结构
1.在线上生产环境,JVM 的 Xms 和 Xmx 设置一样大小的内存容量,避免在 GC 后调整堆大小带来的压力. 2.给 JVM 环境参数设置-XX:+HeapDumpOnOutOfMemoryEr ...
- AgileConfig - RESTful API 介绍
AgileConfig AgileConfig是一个基于.net core开发的轻量级配置中心. AgileConfig秉承轻量化的特点,部署简单.配置简单.使用简单.学习简单,它只提取了必要的一些功 ...
- kubernetes机理之调度器以及控制器
一 了解调度器 1.1 调度器是如何将一个pod调度到节点上的 我们都已然知晓了,API服务器不会主动的去创建pod,只是拉起系统组件,这些组件订阅资源状态的通知,之后创建相应的资源,而负责调度po ...