编辑
2025-10-14
C#
00

目录

技术亮点:平滑动画与精细控制
基础实现
添加动画效果
总结

Toggle Button(开关按钮)是一个常见的UI控件,用于表示两种状态之间的切换(开/关、是/否等)。本文将详细介绍如何在C#中实现一个自定义的Toggle Button控件。

Toggle Button(开关按钮)是一个常见的UI控件,用于表示两种状态之间的切换(开/关、是/否等)。本文将详细介绍如何在C#中实现一个自定义的Toggle Button控件。

技术亮点:平滑动画与精细控制

我们的切换按钮具备以下关键特性:

  1. 流畅动画:采用计时器实现像素级平滑切换
  2. 高度可定制:支持自定义颜色、边框和样式
  3. 抗锯齿渲染:使用SmoothingMode.AntiAlias确保视觉质量

基础实现

首先,我们需要继承CheckBox控件来创建我们的Toggle Button:

C#
using System; using System.Collections.Generic; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Threading.Tasks; using Timer = System.Windows.Forms.Timer; namespace AppControls { public class ToggleButton : CheckBox { // 定义私有字段 private Color _onBackColor = Color.MediumSlateBlue; private Color _onToggleColor = Color.WhiteSmoke; private Color _offBackColor = Color.Gray; private Color _offToggleColor = Color.Gainsboro; // 当前开关状态 private bool _isOn = false; private int _toggleSize; public ToggleButton() { this.MinimumSize = new Size(45, 22); // 设置控件样式 this.Cursor = Cursors.Hand; // 启用双缓冲,减少闪烁 this.DoubleBuffered = true; } // 自定义属性 public Color OnBackColor { get => _onBackColor; set { _onBackColor = value; this.Invalidate(); } } public Color OnToggleColor { get => _onToggleColor; set { _onToggleColor = value; this.Invalidate(); } } public Color OffBackColor { get => _offBackColor; set { _offBackColor = value; this.Invalidate(); } } public Color OffToggleColor { get => _offToggleColor; set { _offToggleColor = value; this.Invalidate(); } } public virtual bool Checked { get => _isOn; set { _isOn = value; this.Invalidate(); } } protected override void OnPaint(PaintEventArgs pevent) { base.OnPaint(pevent); Graphics g = pevent.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; pevent.Graphics.Clear(this.Parent.BackColor); // 计算控件尺寸 int toggleSize = this.Height - 5; _toggleSize = toggleSize; // 创建绘图路径 using (GraphicsPath path = new GraphicsPath()) { // 绘制背景 path.AddArc(0, 0, this.Height, this.Height, 90, 180); path.AddArc(this.Width - this.Height, 0, this.Height, this.Height, 270, 180); path.CloseFigure(); // 设置背景颜色 g.FillPath(new SolidBrush(_isOn ? _onBackColor : _offBackColor), path); // 绘制开关按钮 float toggleLocation = _isOn ? this.Width - this.Height + 2 : 2; g.FillEllipse(new SolidBrush(_isOn ? _onToggleColor : _offToggleColor), toggleLocation, 2, toggleSize, toggleSize); } } protected override void OnClick(EventArgs e) { this._isOn = !this._isOn; base.OnClick(e); this.Invalidate(); // 重绘控件 } protected override void OnResize(EventArgs e) { base.OnResize(e); } } }

添加动画效果

C#
using System; using System.Collections.Generic; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Threading.Tasks; using Timer = System.Windows.Forms.Timer; namespace AppControls { public class ToggleButton : CheckBox { // 定义私有字段 private Color _onBackColor = Color.MediumSlateBlue; private Color _onToggleColor = Color.WhiteSmoke; private Color _offBackColor = Color.Gray; private Color _offToggleColor = Color.Gainsboro; private int _border = 1; // 当前开关状态 private bool _isOn = false; // 动画相关字段 private float _toggleLocation; private readonly Timer _animationTimer; private const int ANIMATION_SPEED = 4; // 动画速度 private int _toggleSize; public ToggleButton() { this.MinimumSize = new Size(45, 22); // 设置控件样式 this.Cursor = Cursors.Hand; // 启用双缓冲,减少闪烁 this.DoubleBuffered = true; // 初始化动画计时器 _animationTimer = new Timer(); _animationTimer.Interval = 1; // 1毫秒间隔 _animationTimer.Tick += AnimationTimer_Tick; } private void AnimationTimer_Tick(object sender, EventArgs e) { float targetLocation = _isOn ? this.Width - this.Height + 2 : 2; // 计算动画步进 if (Math.Abs(_toggleLocation - targetLocation) > ANIMATION_SPEED) { _toggleLocation += _isOn ? ANIMATION_SPEED : -ANIMATION_SPEED; this.Invalidate(); } else { _toggleLocation = targetLocation; _animationTimer.Stop(); this.Invalidate(); } } // 自定义属性 public Color OnBackColor { get => _onBackColor; set { _onBackColor = value; this.Invalidate(); } } public int Border { get { return _border; } set { _border = value; this.Invalidate(); } } public Color OnToggleColor { get => _onToggleColor; set { _onToggleColor = value; this.Invalidate(); } } public Color OffBackColor { get => _offBackColor; set { _offBackColor = value; this.Invalidate(); } } public Color OffToggleColor { get => _offToggleColor; set { _offToggleColor = value; this.Invalidate(); } } public virtual bool Checked { get => _isOn; set { if (_isOn != value) { _isOn = value; StartAnimation(); } } } private void StartAnimation() { if (!_animationTimer.Enabled) { _animationTimer.Start(); } } protected override void OnPaint(PaintEventArgs pevent) { base.OnPaint(pevent); Graphics g = pevent.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; pevent.Graphics.Clear(this.Parent.BackColor); // 计算控件尺寸 int toggleSize = this.Height - 5; _toggleSize = toggleSize; // 创建绘图路径 using (GraphicsPath path = new GraphicsPath()) { // 绘制背景 int arcHeight = this.Height - 1; Rectangle leftArc = new Rectangle(0, 0, arcHeight, arcHeight); Rectangle rightArc = new Rectangle(this.Width - arcHeight - 2, 0, arcHeight, arcHeight); path.StartFigure(); path.AddArc(leftArc, 90, 180); path.AddArc(rightArc, 270, 180); path.CloseFigure(); if (Border > 0) { pevent.Graphics.DrawPath(new Pen(_onBackColor, Border), path); } else { // 设置背景颜色 g.FillPath(new SolidBrush(_isOn ? _onBackColor : _offBackColor), path); } // 绘制开关按钮 g.FillEllipse(new SolidBrush(_isOn ? _onToggleColor : _offToggleColor), _toggleLocation, 2, toggleSize, toggleSize); } } protected override void OnClick(EventArgs e) { _isOn = !_isOn; StartAnimation(); base.OnClick(e); } protected override void OnResize(EventArgs e) { base.OnResize(e); _toggleLocation = _isOn ? this.Width - this.Height + 2 : 2; } // 确保在控件销毁时停止并清理计时器 protected override void Dispose(bool disposing) { if (disposing) { _animationTimer.Stop(); _animationTimer.Dispose(); } base.Dispose(disposing); } } }

image.png

总结

通过以上步骤,我们实现了一个功能完整的Toggle Button控件。这个控件不仅支持自定义外观(如颜色和大小的调整),还具备流畅的动画效果和良好的性能优化。同时,它拥有完整的事件处理机制,并采用了可扩展的设计理念。在实际应用中,可以根据具体需求对控件进行进一步的定制和优化,以满足不同的使用场景。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!