非常喜欢Metro风格的界面,所以想模仿一下一些UI效果的实现,网上找到了很多,但都是CSS3,WPF等实现,对于XAML和CSS3一窍不通,无奈下只有自己开始写。

基于C#/Winform实现的Win8MetroLoading动画

下面是源码:

  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

相关文章: