开关按钮的艺术:用C#打造炫酷UI控件,轻松提升用户体验!

1. 基础实现:从CheckBox到自定义控件

1.1 继承CheckBox并添加核心属性
using System.Drawing.Drawing2D;  
using System.Windows.Forms;  

namespace CustomControls  
{  
    public class AnimatedToggle : CheckBox  
    {  
        // === 核心属性 ===  
        private Color _onColor = Color.MediumSlateBlue;          // 开状态背景色  
        private Color _offColor = Color.Gray;                    // 关状态背景色  
        private Color _toggleColor = Color.WhiteSmoke;           // 圆点颜色  
        private bool _isOn = false;                              // 当前开关状态  
        private Timer _animationTimer = new Timer();             // 动画计时器  
        private float _togglePosition = 0f;                      // 圆点当前位置(0-1)  

        // === 构造函数初始化 ===  
        public AnimatedToggle()  
        {  
            // 设置最小尺寸和双缓冲  
            this.MinimumSize = new Size(45, 22);  
            this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); // 防止闪烁  

            // 配置动画计时器  
            _animationTimer.Interval = 10; // 每10ms更新一次  
            _animationTimer.Tick += AnimationTimer_Tick;  

            // 隐藏原生CheckBox的勾选框  
            this.FlatAppearance.BorderSize = 0;  
            this.FlatStyle = FlatStyle.Flat;  
            this.Cursor = Cursors.Hand; // 鼠标悬停显示手型  
        }  

        // === 自定义属性 ===  
        public Color OnColor  
        {  
            get => _onColor;  
            set  
            {  
                _onColor = value;  
                this.Invalidate(); // 触发重绘  
            }  
        }  

        public Color OffColor  
        {  
            get => _offColor;  
            set  
            {  
                _offColor = value;  
                this.Invalidate();  
            }  
        }  

        public Color ToggleColor  
        {  
            get => _toggleColor;  
            set  
            {  
                _toggleColor = value;  
                this.Invalidate();  
            }  
        }  
    }  
}  

注释

  • ControlStyles.DoubleBuffer:启用双缓冲,消除绘制闪烁;
  • Timer:用于逐帧动画,每10ms更新一次;
  • SetStyle():确保控件支持平滑渲染和自定义绘制。

1.2 绘制核心逻辑:OnPaint事件
protected override void OnPaint(PaintEventArgs e)  
{  
    base.OnPaint(e);  
    Graphics g = e.Graphics;  
    g.SmoothingMode = SmoothingMode.Antialiased; // 抗锯齿  

    // === 绘制背景 ===  
    using (Brush bgBrush = new SolidBrush(_isOn ? _onColor : _offColor))  
    {  
        g.FillRoundedRectangle(bgBrush, new Rectangle(0, 0, this.Width, this.Height), 12); // 圆角矩形  
    }  

    // === 绘制圆点 ===  
    int toggleRadius = this.Height / 2 - 2;  
    float toggleX = _togglePosition * (this.Width - 2 * toggleRadius); // 动态计算圆心X坐标  
    using (Brush toggleBrush = new SolidBrush(_toggleColor))  
    {  
        g.FillEllipse(toggleBrush,  
            new Rectangle(  
                (int)(toggleX + 1),  
                1,  
                toggleRadius * 2,  
                toggleRadius * 2));  
    }  
}  

注释

  • FillRoundedRectangle:使用圆角矩形模拟开关背景;
  • SmoothingMode.Antialiased:确保边缘平滑无锯齿;
  • _togglePosition:通过动画平滑变化实现圆点移动。

2. 动画实现:平滑切换与缓动效果

2.1 计时器驱动的逐帧动画
private void AnimationTimer_Tick(object sender, EventArgs e)  
{  
    // === 计算动画进度 ===  
    float step = _isOn ? 0.05f : -0.05f; // 开/关方向  
    _togglePosition += step;  

    // === 边界检查 ===  
    if (_togglePosition >= 1.0f) _togglePosition = 1.0f;  
    if (_togglePosition <= 0.0f) _togglePosition = 0.0f;  

    // === 触发重绘 ===  
    this.Invalidate();  

    // === 动画完成判断 ===  
    if ((_isOn && _togglePosition >= 0.95f) || (!_isOn && _togglePosition <= 0.05f))  
    {  
        _animationTimer.Stop();  
        OnValueChanged(); // 触发状态改变事件  
    }  
}  

protected override void OnMouseDown(MouseEventArgs e)  
{  
    base.OnMouseDown(e);  
    _isOn = !_isOn; // 翻转状态  
    _animationTimer.Start(); // 开始动画  
}  

注释

  • step:每帧移动的距离(0.05为5%的宽度);
  • OnValueChanged():在动画结束后触发,通知状态改变;
  • Invalidate():强制控件重绘。

2.2 高级缓动效果(参考WPF缓动公式)
// === 缓动公式实现(如回弹效果) ===  
private float BackEaseOut(float t)  
{  
    float s = 1.70158f; // 回弹系数  
    return (float)(t = t - 1) * t * ((s + 1) * t + s) + 1;  
}  

// === 修改AnimationTimer_Tick实现缓动 ===  
private float _animationProgress = 0f; // 动画进度(0-1)  
private void AnimationTimer_Tick(object sender, EventArgs e)  
{  
    _animationProgress += 0.05f; // 每帧进度增量  
    if (_animationProgress > 1f) _animationProgress = 1f;  

    // 使用缓动公式计算当前位置  
    float easedProgress = BackEaseOut(_animationProgress);  
    _togglePosition = _isOn ? easedProgress : 1f - easedProgress;  

    // ... 其余逻辑同上 ...  
}  

注释

  • BackEaseOut:实现类似弹簧回弹的动画效果;
  • 缓动公式可替换为其他类型(如指数、弹性),实现不同效果。

3. 高级定制:主题切换与无障碍设计

3.1 动态主题适配
// === 主题切换接口 ===  
public void ApplyTheme(Theme theme)  
{  
    switch (theme)  
    {  
        case Theme.Light:  
            OnColor = Color.LightSkyBlue;  
            OffColor = Color.LightGray;  
            ToggleColor = Color.White;  
            break;  
        case Theme.Dark:  
            OnColor = Color.FromArgb(255, 50, 150, 255);  
            OffColor = Color.FromArgb(255, 40, 40, 40);  
            ToggleColor = Color.FromArgb(255, 200, 200, 200);  
            break;  
    }  
    this.Invalidate(); // 应用新主题  
}  

// === 枚举定义 ===  
public enum Theme  
{  
    Light,  
    Dark  
}  

注释

  • 通过ApplyTheme()方法实现主题切换;
  • 可扩展为从配置文件或系统主题获取颜色。

3.2 无障碍支持:键盘与屏幕阅读器
// === 支持键盘操作 ===  
protected override void OnKeyDown(KeyEventArgs e)  
{  
    if (e.KeyCode == Keys.Space)  
    {  
        _isOn = !_isOn;  
        _animationTimer.Start();  
        e.Handled = true;  
    }  
    base.OnKeyDown(e);  
}  

// === 提供ARIA标签(适用于屏幕阅读器) ===  
protected override void OnAccessibleValueChange(AccessibleValueChangeEventArgs e)  
{  
    base.OnAccessibleValueChange(e);  
    this.AccessibleName = _isOn ? "Switch enabled" : "Switch disabled";  
}  

注释

  • OnKeyDown():支持空格键切换;
  • AccessibleName:为屏幕阅读器提供状态描述。

4. 实战案例:权限管理界面的开关应用

4.1 在WinForms中使用自定义控件
// === 窗体代码 ===  
public partial class SettingsForm : Form  
{  
    public SettingsForm()  
    {  
        InitializeComponent();  

        // 初始化开关按钮  
        AnimatedToggle toggle = new AnimatedToggle  
        {  
            OnColor = Color.ForestGreen,  
            OffColor = Color.IndianRed,  
            ToggleColor = Color.White,  
            Location = new Point(20, 20),  
            Size = new Size(80, 30)  
        };  

        // 绑定事件  
        toggle.CheckedChanged += (s, e) =>  
        {  
            MessageBox.Show($"Switch is now {(toggle._isOn ? "ON" : "OFF")}");  
        };  

        this.Controls.Add(toggle);  
    }  
}  

注释

  • 通过CheckedChanged事件响应状态变化;
  • 可扩展为控制后端服务开关。

5. 进阶技巧:动态响应与组合控件

5.1 响应式布局适配
// === 自动调整尺寸 ===  
protected override void OnResize(EventArgs e)  
{  
    base.OnResize(e);  
    this.Width = Math.Max(45, this.Width); // 最小宽度限制  
    this.Height = Math.Max(22, this.Height); // 最小高度限制  
}  

注释

  • 确保控件在父容器缩放时保持最小尺寸。

6. 性能优化:减少重绘开销

// === 优化OnPaint性能 ===  
protected override void OnPaintBackground(PaintEventArgs pevent)  
{  
    // 禁用背景重绘(由OnPaint统一处理)  
    return;  
}  

// === 使用双缓冲 ===  
protected override CreateParams CreateParams  
{  
    get  
    {  
        CreateParams cp = base.CreateParams;  
        cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED,启用双缓冲  
        return cp;  
    }  
}  

注释

  • WS_EX_COMPOSITED:启用双缓冲减少闪烁;
  • OnPaintBackground():避免重复绘制背景。

通过以上6大核心技术,你已经掌握了C#开关按钮的“核武器库”:

  • 平滑动画:用计时器+缓动公式实现丝滑切换;
  • 主题适配:一键切换暗/亮模式;
  • 无障碍支持:键盘操作与屏幕阅读器兼容;
  • 性能优化:双缓冲与响应式布局保障流畅体验;
  • 实战应用:直接集成到权限管理、设置面板等场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值