C#/Winform实现Win8MetroLoading动画
时间:2014-06-03 15:36:01
收藏:0
阅读:603
非常喜欢Metro风格的界面,所以想模仿一下一些UI效果的实现,网上找到了很多,但都是CSS3,WPF等实现,对于XAML和CSS3一窍不通,无奈下只有自己开始写。
下面是源码:
Dot.cs
1 using System.Drawing; 2 3 namespace MetroLoading 4 { 5 /// <summary> 6 /// 表示一个"点" 7 /// </summary> 8 public sealed class Dot 9 { 10 #region 字段/属性 11 12 /// <summary> 13 /// 当前帧绘图坐标,在每次DoAction()时重新计算 14 /// </summary> 15 public PointF Location; 16 17 //点相对于圆心的角度,用于计算点的绘图坐标 18 private int _angle; 19 20 //速度 21 private int _speed; 22 //表示动画进度,用于圈数判断 23 private int _progress; 24 //透明度 25 private int _opacity; 26 /// <summary> 27 /// 透明度 28 /// </summary> 29 public int Opacity 30 { 31 get { return _opacity < minOpacity ? minOpacity : _opacity; } 32 } 33 34 #endregion 35 36 #region 常量 37 38 //最小/最大速度 39 private const int minSpeed = 2; 40 private const int maxSpeed = 10; 41 42 //出现区的相对角度 43 private const int appearAngle = 135; 44 //减速区的相对角度 45 private const int slowAngle = 225; 46 //加速区的相对角度 47 private const int quickAngle = 315; 48 49 //最小/最大角度 50 private const int minAngle = 0; 51 private const int maxAngle = 360; 52 53 //淡出速度 54 private const int alphaSub = 30; 55 56 //最小/最大透明度 57 private const int minOpacity = 0; 58 private const int maxOpacity = 255; 59 60 #endregion 常量 61 62 //构造 63 public Dot() 64 { 65 Reset(); 66 } 67 68 #region 方法 69 70 /// <summary> 71 /// 重新计算当前帧绘图坐标 72 /// </summary> 73 private void ReCalcLocation() 74 { 75 this.Location = Common.GetDotLocationByAngle(Form1.CircleCenter, Form1.CircleRadius, _angle); 76 } 77 78 /// <summary> 79 /// 点动作 80 /// </summary> 81 public void DotAction() 82 { 83 switch (_progress) 84 { 85 case 0: 86 { 87 _opacity = maxOpacity; 88 AddSpeed(); 89 if (_angle + _speed >= slowAngle && _angle + _speed < quickAngle) 90 { 91 _progress = 1; 92 _angle = slowAngle - _speed; 93 } 94 } 95 break; 96 case 1: 97 { 98 SubSpeed(); 99 if (_angle + _speed >= quickAngle || _angle + _speed < slowAngle) 100 { 101 _progress = 2; 102 _angle = quickAngle - _speed; 103 } 104 } 105 break; 106 case 2: 107 { 108 AddSpeed(); 109 if (_angle + _speed >= slowAngle && _angle + _speed < quickAngle) 110 { 111 _progress = 3; 112 _angle = slowAngle - _speed; 113 } 114 } 115 break; 116 case 3: 117 { 118 SubSpeed(); 119 if (_angle + _speed >= quickAngle && _angle + _speed < maxAngle) 120 { 121 _progress = 4; 122 _angle = quickAngle - _speed; 123 } 124 } 125 break; 126 case 4: 127 { 128 SubSpeed(); 129 if (_angle + _speed >= minAngle && _angle + _speed < appearAngle) 130 { 131 _progress = 5; 132 _angle = minAngle; 133 } 134 } 135 break; 136 case 5: 137 { 138 AddSpeed(); 139 FadeOut(); 140 } 141 break; 142 } 143 144 //移动 145 _angle = _angle >= (maxAngle - _speed) ? minAngle : _angle + _speed; 146 //重新计算坐标 147 ReCalcLocation(); 148 } 149 150 //淡出 151 private void FadeOut() 152 { 153 _opacity -= alphaSub; 154 if (_opacity <= 0) 155 this._angle = appearAngle; 156 } 157 158 //重置状态 159 public void Reset() 160 { 161 _angle = appearAngle; 162 _speed = minSpeed; 163 _progress = 0; 164 _opacity = 1; 165 } 166 167 //加速 168 private void AddSpeed() 169 { 170 if (++_speed >= maxSpeed) _speed = maxSpeed; 171 } 172 173 //减速 174 private void SubSpeed() 175 { 176 if (--_speed <= minSpeed) _speed = minSpeed; 177 } 178 179 #endregion 方法 180 } 181 }
Common.cs
1 using System; 2 using System.Drawing; 3 4 namespace MetroLoading 5 { 6 public static class Common 7 { 8 /// <summary> 9 /// 根据半径、角度求圆上坐标 10 /// </summary> 11 /// <param name="radius">半径</param> 12 /// <param name="angle">角度</param> 13 /// <returns>坐标</returns> 14 public static PointF GetDotLocationByAngle(Point center, int radius, int angle) 15 { 16 float x, y; 17 18 x = (float)(center.X + radius * Math.Cos(angle * Math.PI / 180)); 19 y = (float)(center.Y + radius * Math.Sin(angle * Math.PI / 180)); 20 21 return new PointF(x, y); 22 } 23 } 24 }
Form1.cs
1 using System; 2 using System.Drawing; 3 using System.Windows.Forms; 4 using System.Linq; 5 using System.Threading; 6 7 namespace MetroLoading 8 { 9 public partial class Form1 : Form 10 { 11 #region 字段 12 13 //点数组 14 private Dot[] _dots; 15 16 //数据tmr 17 private System.Threading.Timer _actionTmr; 18 //绘图tmr 19 private System.Windows.Forms.Timer _graphicsTmr; 20 21 //圆心 22 public static readonly Point CircleCenter = new Point(75, 75); 23 //半径 24 public static readonly int CircleRadius = 50; 25 //点大小 26 private static readonly Size DotSize = new Size(8, 8); 27 28 //是否绘制:用于状态重置时挂起与恢复绘图 29 private bool isDrawing = true; 30 31 //timer计数:用于延迟启动每个点 32 private int timerCount = 0; 33 34 #endregion 字段 35 36 #region 常量 37 38 //动作间隔 39 private const int actionInterval = 30; 40 //绘制间隔 41 private const int drawInterval = 1; 42 43 //计数基数:用于计算每个点启动延迟:index * timerCountRadix 44 private const int timerCountRadix = 40; 45 46 #endregion 常量 47 48 #region 构造 49 50 public Form1() 51 { 52 InitializeComponent(); 53 54 //双缓冲,禁擦背景 55 this.SetStyle( 56 ControlStyles.AllPaintingInWmPaint 57 | ControlStyles.UserPaint 58 | ControlStyles.OptimizedDoubleBuffer, 59 true); 60 61 //初始化绘图timer 62 _graphicsTmr = new System.Windows.Forms.Timer(); 63 _graphicsTmr.Interval = 1; 64 //Invalidate()强制重绘,绘图操作在OnPaint中实现 65 _graphicsTmr.Tick += (sender1, e1) => this.pictureBox1.Invalidate(false); 66 67 //初始化"点" 68 _dots = new Dot[5]; 69 for (int i = 0; i < _dots.Length; ++i) 70 _dots[i] = new Dot(); 71 } 72 73 #endregion 构造 74 75 //检查是否重置 76 private bool CheckToReset() 77 { 78 return _dots.Count((d) => d.Opacity > 0) == 0; 79 } 80 81 #region 事件处理 82 83 //开关 84 private void btnSwitch_Click(object sender, EventArgs e) 85 { 86 if (_graphicsTmr.Enabled) 87 { 88 _graphicsTmr.Stop(); 89 _actionTmr.Dispose(); 90 } 91 else 92 { 93 _graphicsTmr.Start(); 94 95 //初始化动作timer 96 _actionTmr = new System.Threading.Timer( 97 (state) => 98 { 99 //动画动作 100 for (int i = 0; i < _dots.Length; i++) 101 if (timerCount++ > i * timerCountRadix) 102 _dots[i].DotAction(); 103 104 //是否重置 105 if (CheckToReset()) 106 { 107 //重置前暂停绘图 108 isDrawing = false; 109 110 timerCount = 0; 111 112 for (int i = 0; i < _dots.Length; i++) 113 _dots[i].Reset(); 114 115 //恢复绘图 116 isDrawing = true; 117 } 118 119 _actionTmr.Change(actionInterval, System.Threading.Timeout.Infinite); 120 }, 121 null, actionInterval, System.Threading.Timeout.Infinite); 122 } 123 } 124 125 //重绘 126 private void pictureBox1_Paint(object sender, PaintEventArgs e) 127 { 128 if (isDrawing) 129 { 130 //抗锯齿 131 e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; 132 133 using (Bitmap bmp = new Bitmap(200, 200)) 134 { 135 //缓冲绘制 136 using (Graphics bufferGraphics = Graphics.FromImage(bmp)) 137 { 138 //抗锯齿 139 bufferGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; 140 for (int i = 0; i < _dots.Length; ++i) 141 { 142 RectangleF rect = new RectangleF( 143 new PointF(_dots[i].Location.X - DotSize.Width / 2, _dots[i].Location.Y - DotSize.Height / 2), 144 DotSize); 145 146 bufferGraphics.FillEllipse(new SolidBrush(Color.FromArgb(_dots[i].Opacity, Color.White)), rect); 147 } 148 } 149 150 //贴图 151 e.Graphics.DrawImage(bmp, new PointF(0, 0)); 152 }//bmp disposed 153 } 154 } 155 156 #endregion 事件处理 157 158 }//end of class Form1 159 }//end of namespace
Form1.Designer.cs
1 namespace MetroLoading 2 { 3 partial class Form1 4 { 5 /// <summary> 6 /// 必需的设计器变量。 7 /// </summary> 8 private System.ComponentModel.IContainer components = null; 9 10 /// <summary> 11 /// 清理所有正在使用的资源。 12 /// </summary> 13 /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param> 14 protected override void Dispose(bool disposing) 15 { 16 if (disposing && (components != null)) 17 { 18 components.Dispose(); 19 } 20 base.Dispose(disposing); 21 } 22 23 #region Windows 窗体设计器生成的代码 24 25 /// <summary> 26 /// 设计器支持所需的方法 - 不要 27 /// 使用代码编辑器修改此方法的内容。 28 /// </summary> 29 private void InitializeComponent() 30 { 31 this.btnSwitch = new System.Windows.Forms.Button(); 32 this.lblNote = new System.Windows.Forms.Label(); 33 this.pictureBox1 = new System.Windows.Forms.PictureBox(); 34 ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); 35 this.SuspendLayout(); 36 // 37 // btnSwitch 38 // 39 this.btnSwitch.Location = new System.Drawing.Point(58, 206); 40 this.btnSwitch.Name = "btnSwitch"; 41 this.btnSwitch.Size = new System.Drawing.Size(75, 23); 42 this.btnSwitch.TabIndex = 0; 43 this.btnSwitch.Text = "switch"; 44 this.btnSwitch.UseVisualStyleBackColor = true; 45 this.btnSwitch.Click += new System.EventHandler(this.btnSwitch_Click); 46 // 47 // lblNote 48 // 49 this.lblNote.AutoSize = true; 50 this.lblNote.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); 51 this.lblNote.ForeColor = System.Drawing.Color.White; 52 this.lblNote.Location = new System.Drawing.Point(5, 255); 53 this.lblNote.Name = "lblNote"; 54 this.lblNote.Size = new System.Drawing.Size(208, 24); 55 this.lblNote.TabIndex = 1; 56 this.lblNote.Text = "Coded by coffee,\r\nEmail:muxiang1992@outlook.com"; 57 // 58 // pictureBox1 59 // 60 this.pictureBox1.BackColor = System.Drawing.Color.Black; 61 this.pictureBox1.Location = new System.Drawing.Point(0, 0); 62 this.pictureBox1.Name = "pictureBox1"; 63 this.pictureBox1.Size = new System.Drawing.Size(200, 200); 64 this.pictureBox1.TabIndex = 2; 65 this.pictureBox1.TabStop = false; 66 this.pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint); 67 // 68 // Form1 69 // 70 this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 71 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 72 this.BackColor = System.Drawing.Color.Black; 73 this.ClientSize = new System.Drawing.Size(252, 303); 74 this.Controls.Add(this.pictureBox1); 75 this.Controls.Add(this.lblNote); 76 this.Controls.Add(this.btnSwitch); 77 this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; 78 this.MaximizeBox = false; 79 this.MinimizeBox = false; 80 this.Name = "Form1"; 81 this.Text = "Metro Loading"; 82 this.TopMost = true; 83 ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); 84 this.ResumeLayout(false); 85 this.PerformLayout(); 86 87 } 88 89 #endregion 90 91 private System.Windows.Forms.Button btnSwitch; 92 private System.Windows.Forms.Label lblNote; 93 private System.Windows.Forms.PictureBox pictureBox1; 94 } 95 }
PS:有些地方肯定还有一些不协调,没办法,笔者审美有限,请大家通过代码内常量进行微调。欢迎大神们指点……
评论(0)