非常喜欢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 }