skip to Main Content

If we want to slide the screen, we need some events.

Like Mouse Move Event, Mouse Down Event, Mouse UP event
But the problem is we only can do some animation only when the finger touch the screen, I mean: when It touch the screen move, it will move, when we release it, it will stop(or give it a position let it stop to there). But I want some animation like IPhone main screen do. If our finger slide more fast, the animation more fast (or the animation slide to more far place).

Just like now we use the Photoshop, when the picture zoom out to very large, when we move the hand more fast, it will move to very far.

Another example is it will slow down very slowly, not immediately.
Also it will know my finger sliding fast , or slow….then it will slide slow or fast…

2

Answers


  1. This is a quick example of a control I did for a test with inertia, using a ScrollViewer.
    Hope this helps.

    public partial class HomeFeed : BaseControl
    {
        public HomeFeed()
        {
            InitializeComponent();
        }
    
        private bool IsDragging
        {
            get { return _isDragging; }
            set
            {
                var start = _isDragging && !value;
                _isDragging = value;
    
                if (start)
                {
                    new Thread(x =>
                    {
                        var c = 0;
                        while (ApplyVelocity())
                        {
                            c++;
                            Thread.Sleep(15);
                        }
    
                    }).Start();
                }
            }
        }
    
        private Point _mousePosition;
        private Velocity _velocity = new Velocity();
        private bool _isDragging;
    
        private void HomeScrollViewer_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            IsDragging = true;
            _velocity.Reset();
            _mousePosition = e.GetPosition(this);
            e.Handled = true;
        }
    
        private void HomeScrollViewer_OnPreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (!IsDragging) return;
    
            var pos = e.GetPosition(this);
            var y = pos.Y - _mousePosition.Y;
    
            if (y == 0)
            {
                return;
            }
    
            _velocity.TryUpdate(y);
    
            HomeScrollViewer.ScrollToVerticalOffset(HomeScrollViewer.VerticalOffset - y);
            _mousePosition = pos;
        }
    
        private void HomeScrollViewer_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!IsDragging) return;
    
            IsDragging = false;
            e.Handled = true;
        }
    
        private void HomeScrollViewer_OnMouseLeave(object sender, MouseEventArgs e)
        {
            if (!IsDragging) return;
    
            IsDragging = false;
            e.Handled = true;
        }
    
        private bool ApplyVelocity()
        {
            if (IsDragging || _velocity.Value == 0)
            {
                return false;
            }
    
            Dispatcher.BeginInvoke(new Action(() => HomeScrollViewer.ScrollToVerticalOffset(HomeScrollViewer.VerticalOffset - _velocity.Value)));
    
            var size = Math.Abs(_velocity.Value);
            var sign = size / _velocity.Value;
    
            _velocity.Value = sign * Math.Max(0, Math.Min(size*0.95, size - 1));
            return true;
        }
    }
    
    public class Velocity
    {
        private readonly int _timespan;
        public double Value { get; set; }
        public DateTime SetAt { get; set; }
    
        public Velocity(int timespan = 1000)
        {
            _timespan = timespan;
            Value = 0;
            SetAt = DateTime.Now;
        }
    
        public void TryUpdate(double value)
        {
            if (value == 0)
            {
                return;
            }
    
            if (SetAt.Add(TimeSpan.FromMilliseconds(_timespan)) > DateTime.Now)
            {
                SetAt = DateTime.Now;
                Value = value;
                return;
            }
    
            if (value*Value < 0)
            {
                SetAt = DateTime.Now;
                Value = value;
                return;
            }
    
            if (Math.Abs(value) > Math.Abs(Value))
            {
                SetAt = DateTime.Now;
                Value = value;
                return;
            }
        }
    
        public void Reset()
        {
            Value = 0;
            SetAt = DateTime.Now;
        }
    }
    
    Login or Signup to reply.
  2. I use a modified version of the the code found here in my own programs. Usage is simple as it is an attached behavior and can be applied to a style so that all of your scroll viewers automatically behave in this way. It works by using the same (tunneled) events you mention (OnPreviewMouseDown, OnPreviewMouseUp, and OnPreviewMouseMove). During the handling of OnPreviewMouseMove, inertia is calculated and the scrollbar is moved in a simulated physical manner. There is also a friction property which can be set to change the length of time a scrollbar “glides”.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search