Winform中的开关按钮【ToggleButton】

直接看效果图了,不想拷贝代码了

Winform中的开关按钮【ToggleButton】_第1张图片

源码下载

下载的源码里面是没有动画切换效果的,下面贴出的代码是修改后带动画效果的源码,两个类:ToggleButtonStyle.csToggleButton.cs

Winform中的开关按钮【ToggleButton】_第2张图片

下面是修改后的带切换动画的效果的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ToggleButtonTest.ToggleButton.TypeConverters;
using System.Drawing.Drawing2D;
using ToggleButtonTest.ToggleButton.Common;

namespace ToggleButtonTest.ToggleButton
{
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(CheckBox))]
    public partial class ToggleButton : Control
    {
        private ToggleButtonStyle _ToggleButtonStyle;
        private Rectangle _MouseRect;
        private bool _Checked;
        private Color _StateColor;
        private bool _DotFocus;
        private bool _DotClick;
        private bool _EnabledToggle = true;
        //动画效果移动距离
        private int _EffectDistance=0;
        //DOT是否移动
        private bool _IsMoving = false;

        /// 
        /// ToggleButton状态改变
        /// 返回true,ToggleButton状态改变,否则状态回滚
        /// 
        /// 
        public delegate bool DelToggleStateChanged(bool isChecked);
        [Browsable(true), Description("ToggleButton状态改变")]
        public event DelToggleStateChanged OnToggleStateChanged;

        public ToggleButton()
        {
            InitializeComponent();
            this.Size = new Size(70, 35);
            _ToggleButtonStyle = new ToggleButtonStyle(this);
            //SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(
                ControlStyles.UserPaint |
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.ResizeRedraw |
                ControlStyles.SupportsTransparentBackColor |
                ControlStyles.UserMouse |
                ControlStyles.Selectable |
                ControlStyles.StandardClick, true);
        }

        [Browsable(true), Description("ToggleButton样式设置"), Category("ToggleButton")]
        [Localizable(true)]
        [MergableProperty(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ToggleButtonStyle ButtonStyle
        {
            get
            {
                return _ToggleButtonStyle;
            }
            set
            {
                _ToggleButtonStyle = value;
            }
        }

        /// 
        /// 设置ToggleButton可操作性,相当于Enabled
        /// 
        [Browsable(true), Description("设置ToggleButton可操作性")]
        public bool EnabledToggle
        {
            get
            {
                return _EnabledToggle;
            }
            set
            {
                if (_EnabledToggle != value)
                {
                    _EnabledToggle = value;
                    _DotClick = false;
                    _DotFocus = false;
                    this.Invalidate();
                }
            }
        }

        /// 
        /// 请使用EnableToogle
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new bool Enabled { get { return false; } set { } }



        /// 
        /// ToggleButton是否选中
        /// 
        [Browsable(true), Description("ToggleButton是否选中")]
        public bool Checked
        {
            get
            {
                return _Checked;
            }
            set
            {
                //如果value值未改变,则放弃执行,减少UI渲染,避免不必要的刷新Invalidate()
                if (_Checked == value)
                {
                    return;
                }
                if (_IsMoving)
                {
                    return;
                }
                _DotClick = false;
                _DotFocus = false;
                _Checked = value;
                if (ButtonStyle.AnimateEnable)
                {
                    _EffectDistance = !value ? FixedMoveEndDistance : FixedMoveStartPosition;
                    PlayAnimate();
                }
                else
                {
                    this.Invalidate();
                }
            }
        }

        private Timer timer;

        private void PlayAnimate()
        {
            _IsMoving = true;
            if (timer != null)
            {
                timer.Enabled = false;
                timer = null;
            }
            timer = new Timer();
            timer.Tick += Animate_Effect;
            timer.Interval = 30;//30ms执行一次;
            timer.Enabled = true;
        }

        private void Animate_Effect(object sender, EventArgs e)
        {
            //每次移动5px;
            //取消选中
            var endAnimate = false;
            if (!_Checked)
            {
                _EffectDistance -=ButtonStyle.AnimateDisp;
                if (_EffectDistance <= FixedMoveStartPosition)
                {
                    _EffectDistance = FixedMoveStartPosition;
                    endAnimate = true;
                }
            }
            else
            {
                _EffectDistance += ButtonStyle.AnimateDisp;
                if (_EffectDistance >= FixedMoveEndDistance)
                {
                    _EffectDistance = FixedMoveEndDistance;
                    endAnimate = true;
                }
            }
            if (endAnimate)
            {
                _IsMoving = false;
                if (timer != null)
                {
                    timer.Enabled = false;
                    timer = null;
                }
            }
            //刷新视图
            this.Invalidate();
        }

        private int MovingX
        {
            get
            {
                if (_IsMoving)
                {
                    return _EffectDistance;
                }
                else
                {
                    return _Checked ? FixedMoveEndDistance : FixedMoveStartPosition;
                }
            }
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (_MouseRect != null && _MouseRect.Contains(new Point(e.X, e.Y)) && this.EnabledToggle)
                {
                    Checked = !Checked;
                    if (OnToggleStateChanged != null)
                    {
                        var suc = OnToggleStateChanged(Checked);
                        if (!suc)
                        {
                            Checked = !Checked;
                        }
                    }
                }
            }
            base.OnMouseClick(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            var dotFocus = EnabledToggle && _MouseRect != null && _MouseRect.Contains(new Point(e.X, e.Y));
            if (_DotFocus != dotFocus)
            {
                _DotFocus = dotFocus;
                this.Invalidate();
            }
            base.OnMouseMove(e);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                _DotClick = EnabledToggle && _MouseRect != null && _MouseRect.Contains(new Point(e.X, e.Y));
                if (_DotClick)
                {
                    this.Invalidate();
                }
            }
            base.OnMouseDown(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (_DotClick)
            {
                _DotClick = false;
                this.Invalidate();
            }
            base.OnMouseDown(e);
        }

        /// 
        /// 圆圈固定移动终止距离
        /// 
        private int FixedMoveEndDistance
        {
            get
            {
                //DOT大小
                var dotDis = this.ClientRectangle.Width > this.ClientRectangle.Height ? this.Height : this.Width;
                dotDis = dotDis - 2 * ButtonStyle.DotDistance - 2 * ButtonStyle.BorderWidth;
                //会与DOT冲突
                var distance= this.ClientRectangle.Width > this.ClientRectangle.Height ? this.Width : this.Height;
                distance =distance-dotDis-ButtonStyle.BorderWidth-ButtonStyle.DotDistance;
                return distance;
            }
        }

        /// 
        /// 圆圈固定移动起始位置
        /// 
        public int FixedMoveStartPosition
        {
            get
            {
                return ButtonStyle.BorderWidth + ButtonStyle.DotDistance;
            }
        }


        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;  //使绘图质量最高,即消除锯齿
            var dotDis = this.ClientRectangle.Width > this.ClientRectangle.Height ? this.Height : this.Width;
            var rect = new Rectangle(0, 0, this.ClientRectangle.Width - 1, this.ClientRectangle.Height - 1);
            var bRect = new Rectangle(0, 0, this.ClientRectangle.Width - 1, this.ClientRectangle.Height - 1);
            var roundRectR = new RectangleR(rect, dotDis / 2);
            var borderRectR = new RectangleR(bRect, dotDis / 2);

            //画背景
            FillRectangle(e.Graphics, roundRectR, ButtonStyle.ToggleButtonBackColor);

            var x = ButtonStyle.DotDistance;
            dotDis = dotDis - 2 * x - 2 * ButtonStyle.BorderWidth;
            var y = (this.ClientRectangle.Height - dotDis) / 2;
            var starX = MovingX;
            if (Checked&&!ButtonStyle.AnimateEnable)
            {
               starX = this.ClientRectangle.Width  - dotDis-x-ButtonStyle.BorderWidth;
            }

            //Dot区域
            _MouseRect = new Rectangle(starX, y, dotDis, dotDis);

            _StateColor = ButtonStyle.ToggleOffColor;
            if (Checked)
            {
                _StateColor = ButtonStyle.ToggleOnColor;
            }

            if (EnabledToggle == false)
            {
                _StateColor = ColorTranslator.FromHtml("#c0bfbf");
            }

            //画边框
            DrawPathBorder(e.Graphics, borderRectR, _StateColor, ButtonStyle.BorderWidth);

            //处理dot
            if (_DotFocus&&!_IsMoving)
            {
                _StateColor = ButtonStyle.ToggleOffFocusColor;
                if (Checked)
                {
                    _StateColor = ButtonStyle.ToggleOnFocusColor;
                }
            }

            if (_DotClick&&!_IsMoving)
            {
                var offColor = ButtonStyle.ToggleOffColor;
                var offX = -2;
                if (Checked)
                {
                    offX = 2;
                    offColor = ButtonStyle.ToggleOnColor;
                }
                //画阴影
                var offRect = _MouseRect;
                offRect.Offset(offX, 0);
                using (var brush = new SolidBrush(offColor))
                {
                    e.Graphics.FillEllipse(brush, offRect);
                }
                
            }

            //画圆DOT
            using (var brush = new SolidBrush(_StateColor))
            {
                e.Graphics.FillEllipse(brush, _MouseRect);
            }
            e.Graphics.ResetClip();
        }

        private void FillRectangle(Graphics g, RectangleR roundRect, Color color)
        {
            if (roundRect.Rect.Width <= 0 || roundRect.Rect.Height <= 0)
            {
                return;
            }

            using (GraphicsPath path = roundRect.ToGraphicsBezierPath())
            {
                using (Brush brush = new SolidBrush(color))
                {
                    g.FillPath(brush, path);
                }
            }
        }

        private void DrawPathBorder(Graphics g, RectangleR roundRect, Color color, int borderWidth)
        {
            using (GraphicsPath path = roundRect.ToGraphicsBezierPath())
            {
                using (Pen pen = new Pen(color, borderWidth))
                {
                    g.DrawPath(pen, path);
                }
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ToggleButtonTest.ToggleButton.TypeConverters
{
    /// 
    /// ToggleButton属性样式设置
    /// 
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public class ToggleButtonStyle
    {
        private Control _control;

        private Color _ToggleOnColor;
        private Color _ToggleOffColor;
        private Color _ToggleButtonBackColor;
        private int _DotDistance;
        private int _BorderWidth;
        private Color _ToggleOnFocusColor;
        private Color _ToggleOffFocusColor;
        private bool _AnimateEnable = true;
        //使用动画时的位移量
        private int _AnimateDisp= 10;

        public ToggleButtonStyle(Control control)
        {
            this._control = control;
            this._ToggleOnColor = ColorTranslator.FromHtml("#0099ff");
            this._ToggleOffColor = Color.Gray;
            this._ToggleButtonBackColor = Color.White;
            this._DotDistance = 4;
            this._BorderWidth = 1;
            this._ToggleOnFocusColor = ColorTranslator.FromHtml("#96d7ff");
            this._ToggleOffFocusColor = ColorTranslator.FromHtml("#c0bfbf");
        }

        /// 
        /// ToggleButton开启动画效果时的偏移量,最小值10px
        /// 
        [Browsable(true), Description("ToggleButton开启动画效果时的偏移量,最小值10px")]
        public int AnimateDisp
        {
            get
            {
                return _AnimateDisp;
            }
            set
            {
                if (value < 10)
                {
                    value = 10;
                }
                _AnimateDisp = value;
            }
        }

        /// 
        /// ToggleButton状态切换时是否开启动画效果
        /// 
        [Browsable(true), Description("ToggleButton状态切换时是否开启动画效果")]
        public bool AnimateEnable
        {
            get
            {
                return _AnimateEnable;
            }
            set
            {
                _AnimateEnable = value;
            }
        }

        /// 
        /// ToggleButton打开时颜色
        /// 
        [Browsable(true), Description("ToggleButton打开时颜色")]
        public Color ToggleOnColor
        {
            get
            {
                return _ToggleOnColor;
            }
            set
            {
                _ToggleOnColor = value;
                _control.Invalidate();
            }
        }

        /// 
        /// ToggleButton打开时获取焦点颜色
        /// 
        [Browsable(true), Description("ToggleButton打开时获取焦点颜色")]
        public Color ToggleOnFocusColor
        {
            get
            {
                return _ToggleOnFocusColor;
            }
            set
            {
                _ToggleOnFocusColor = value;
                _control.Invalidate();
            }
        }

        /// 
        /// ToggleButton关闭时颜色
        /// 
        [Browsable(true), Description("ToggleButton关闭时颜色")]
        public Color ToggleOffColor
        {
            get
            {
                return _ToggleOffColor;
            }
            set
            {
                _ToggleOffColor = value;
                _control.Invalidate();
            }
        }

        /// 
        /// ToggleButton关闭时获取焦点颜色
        /// 
        [Browsable(true), Description("ToggleButton关闭时获取焦点颜色")]
        public Color ToggleOffFocusColor
        {
            get
            {
                return _ToggleOffFocusColor;
            }
            set
            {
                _ToggleOffFocusColor = value;
                _control.Invalidate();
            }
        }

        /// 
        /// ToggleButton背景色,非BackColor
        /// 
        [Browsable(true), Description("ToggleButton背景色,非BackColor")]
        public Color ToggleButtonBackColor
        {
            get
            {
                return _ToggleButtonBackColor;
            }
            set
            {
                _ToggleButtonBackColor = value;
                _control.Invalidate();
            }
        }

        /// 
        /// 圆点到边界的距离
        /// 
        [Browsable(true), Description("圆点到边界的距离")]
        public int DotDistance
        {
            get
            {
                return _DotDistance;
            }
            set
            {
                if (value <= 0)
                {
                    value = 4;
                }
                _DotDistance = value; _control.Invalidate();
            }
        }

        /// 
        /// 边框大小
        /// 
        [Browsable(true), Description("边框大小")]
        public int BorderWidth
        {
            get
            {
                return _BorderWidth;
            }
            set
            {
                if (value <= 0)
                {
                    value = 1;
                }
                _BorderWidth = value; _control.Invalidate();
            }
        }
    }
}

 

你可能感兴趣的:(Winform中的开关按钮【ToggleButton】)