WinForm製作滑動框,實現滾動相冊效果

WinForm製作滑動框,實現鼠標滾動查看效果

    界面層級:

 代碼實現:

  public partial class Form1 : Form
    {
        // 初始時滑動面板所在高度Y
        private int initPanelY;

        // 鼠標鬆開時計算得到的滑動速度
        private double speed = 0;
        // 鼠標按下時得到的指針位置
        private int preCursorY = 0;
        // 鼠標按下的時間
        private DateTime pretime;
        //  鼠標鬆開的時間
        private DateTime curtime;
        // 上一次的鼠標位置
        private Point prePt;

        // tick間隔(0.02s一次) 
        private int interval = 20;
        // 剩餘Tick次數
        private int remainTickTime = 0;

        public Form1()
        {
            InitializeComponent();

            initPanelY = ScrollPanel.Location.Y;
            this.vScrollBar.Scroll += new System.Windows.Forms.ScrollEventHandler(this.ScrollBar_Scroll);
            ScrollPanel.MouseWheel += new MouseEventHandler(this.ScrollPanel_MouseWheel);
            ScrollPanel.MouseDown += new MouseEventHandler(this.ScrollPanel_MouseDown);
            ScrollPanel.MouseUp += new MouseEventHandler(this.ScrollPanel_MouseUp);
            ScrollPanel.MouseMove += new MouseEventHandler(this.ScrollPanel_MouseMove);

            InitTimer();
        }

        /// <summary>
        /// 鼠標按下滑動
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScrollPanel_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                int px = Cursor.Position.X - prePt.X;
                int py = Cursor.Position.Y - prePt.Y;
                ScrollPanel.Location = new Point(ScrollPanel.Location.X, ScrollPanel.Location.Y + py);
                prePt = Cursor.Position;

                ControlVerticalShowRegion();
            }
        }

        /// <summary>
        ///  將滑動面板控制在父面板顯示區域內( Y方向)
        /// </summary>
        private void ControlVerticalShowRegion()
        {
            if (ScrollPanel.Height > BackPanel.Height)
            {
                // 滑到頂部,歸位
                if (ScrollPanel.Location.Y > initPanelY)
                {
                    ScrollPanel.Location = new Point(ScrollPanel.Location.X, initPanelY);
                    timer1.Enabled = false;
                    timer1.Stop();
                }
                // 滑到底部了,歸位(y減高差)
                if (initPanelY + BackPanel.Height > ScrollPanel.Location.Y + ScrollPanel.Height)
                {
                    ScrollPanel.Location = new Point(ScrollPanel.Location.X, initPanelY - (ScrollPanel.Height - BackPanel.Height));
                    timer1.Enabled = false;
                    timer1.Stop();
                }
                // 高差
                int heightDif = ScrollPanel.Height - BackPanel.Height;
                // panel 垂直滾動範圍
                int value = -ScrollPanel.Location.Y;
                double diff = (double)vScrollBar.Maximum - (double)vScrollBar.LargeChange;
                double per = value / diff;
                double p = (double)value / (double)heightDif;
                // 更新滑動條
                vScrollBar.Value = (int)(p * 100);
            }
        }

        /// <summary>
        /// 鼠標懸浮滾動
        /// </summary>
        private void ScrollPanel_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            // 滾動速度
            int scrollSpeed = 20;
            if (ScrollPanel.Height > BackPanel.Height)
            {
                ControlVerticalShowRegion();

                int delta = (e.Delta / Math.Abs(e.Delta)) * scrollSpeed;
                ScrollPanel.Location = new Point(ScrollPanel.Location.X, ScrollPanel.Location.Y + delta);
            }
        }

        /// <summary>
        /// 鬆開左鍵
        /// </summary>
        private void ScrollPanel_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                curtime = DateTime.Now;

                int curPanelY = Cursor.Position.Y;
                // 速度 = 距離 /  時間
                int dis = curPanelY - preCursorY;
                double seconds = (curtime - pretime).TotalMilliseconds;
                speed = (double)dis / seconds;
                // 持續時間
                double durTime = Math.Abs(speed);
                // 總tick次數 = 總共持續時間 durTime*1000 毫秒 / Tick間隔 interval=20
                // 總tick次數
                int tickTime = (int)((durTime * 1000) / interval);
                remainTickTime = tickTime;

                timer1.Interval = interval;
                timer1.Enabled = true;
                timer1.Start();
            }
        }

        /// <summary>
        /// 初始化計時器
        /// </summary>
        private void InitTimer()
        {
            timer1.Interval = interval;
            timer1.Tick += new EventHandler(Timer1_Tick);
        }

        private void Timer1_Tick(object sender, EventArgs e)
        {
            remainTickTime--;
            if (remainTickTime <= 0)
            {
                timer1.Enabled = false;
                timer1.Stop();
                return;
            }        
            // 根據擬合函數 得到y
            double deltaY = EasingCurve(remainTickTime, 0.001);
            int delta = (int)(speed > 0 ? deltaY : -deltaY);

            ScrollPanel.Location = new Point(ScrollPanel.Location.X, ScrollPanel.Location.Y + delta);
            ControlVerticalShowRegion();
        }

        // 擬合曲線 y = x ^ 2[0, durTime],在區間 [ 0, durTime ] 上均勻散列x,隨x的等值遞減y值加速遞減
        /*
        *               |              /
        *               |             /
        *               |            /
        *               |          /
        *               |        /
        *               |     /   
        *               |  /          
        *               |__________________________________
        *             0     <—   tickTime (tick次數)                                                                              
        */
        /// <summary>
        /// 自定義緩動曲線  (本例使用二次函數,當然還有其他更好的擬合數學模型)
        /// </summary>
        private double EasingCurve(double x, double scaleFactor)
        {
            // y=x^2  二次函數
            return x * x * scaleFactor;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 開始加載Form時設置panel高度,可動態爲其添加子元素
            ScrollPanel.Height = 800;
            // ...
        }

        /// <summary>
        /// 滾動條事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            if (ScrollPanel.Height > BackPanel.Height)
            {
                //  滑動條滾動
                int heightDif = ScrollPanel.Height - BackPanel.Height;
                double percent = (double)heightDif / (double)vScrollBar.Maximum;
                double percen = (double)heightDif / ((double)vScrollBar.Maximum - (double)vScrollBar.LargeChange);
                double value = (double)vScrollBar.Value * percen;

                int y = initPanelY - (int)value;
                ScrollPanel.Location = new Point(ScrollPanel.Location.X, y);
            }
        }

        /// <summary>
        /// 鼠標按下
        /// </summary>
        private void ScrollPanel_MouseDown(object sender, MouseEventArgs e)
        {
            prePt = Cursor.Position;
            preCursorY = Cursor.Position.Y;
            pretime = DateTime.Now;

            //timer1.Interval = 5000;
            timer1.Enabled = false;
            timer1.Stop();
        }

    }

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章