If you have ever used an iPhone you will notice the scrolling is very elastic in nature. If you hit the end of the scroll it will go a little further before bouncing back. Also, the faster you flick your finger, the faster the scrolling starts off before gradually slowing down as the scrolling comes to a stop.
I have updated my Image Viewer application (http://www.galacticimg.com) to mimic this behavior. Since it’s not yet touch screen based, you can simply use mouse left click-hold to scroll rather than your finger.
The implementation is pretty straight forward but I am very interested in getting people’s feedback especially if you can think of a more efficient way to accomplish this.
To start, the following event is the event used to monitor for left mouse clicks. Velocity is used to determine the current scroll speed. VerticalOffset is the distance the panel has scrolled so far. The offsets are used to determine the speed of the scroll. As long as the mouse left button is down DraggingPanel will be set to true.
private double _verticalOffset = 0.0;
private double _offset = 0.0;
private double _previousOffset = 0.0;
private int _velocity = 0;
private void PanelCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.Focus();
_draggingPanel = true;
PanelCanvas.CaptureMouse();
_velocity = 0;
_offset = e.GetPosition(this).X - _verticalOffset;
_previousOffset = e.GetPosition(this).X;
}
In the MouseMove event I check to see if the DraggingPanel is true (meaning the left mouse is still down). If so, I calculate the new position of the panel and determine the velocity based upon how fast the mouse is moving. Finally, I set the new position of the ThumbnailCanvas which is the Canvas that contains all my images.
private void PanelCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (true == _draggingPanel)
{
_verticalOffset = e.GetPosition(this).X - _offset;
_velocity = (int)(e.GetPosition(this).X - _previousOffset);
_previousOffset = e.GetPosition(this).X;
ThumbnailCanvas.SetValue(Canvas.LeftProperty, (double)_verticalOffset);
}
}
If the mouse left click up event is fired I set DraggingPanel to false and release the mouse capture.
private void PanelCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
PanelCanvas.ReleaseMouseCapture();
_draggingPanel = false;
}
I have a timer called EllasticScroll() that runs in the background. There are two conditions it checks for:
1. In the case where you scroll beyond the boundary of the images ScrollDistance is set and the panel “bounces back” to position zero. To test this out scroll to the left when you first start the Galactic Image app and you will see the bounce back effect.
2. The left mouse has been released and the auto-scrolling kicks in. It scrolls the panel based upon the current velocity which is trickled down to zero. If the scroll goes 200 pixels beyond the boundary, I stop the velocity setting it to zero and I set ScrollDistance so that is bounces back to zero.
_timer.Interval = TimeSpan.FromMilliseconds(20);
_timer.Tick += new EventHandler(EllasticScroll);
_timer.Start();
private void EllasticScroll(object sender, EventArgs e)
{
if (_scrollDistance != 0)
{
int distance = _scrollDistance / 10;
_scrollCounter++;
if (_scrollCounter == 10)
_scrollDistance = 0;
_verticalOffset += distance;
if (_verticalOffset > 0 && distance > 0)
_verticalOffset = 0.0;
ThumbnailCanvas.SetValue(Canvas.LeftProperty, (double)_verticalOffset);
}
else if (false == _draggingPanel && _velocity != 0)
{
_verticalOffset += _velocity;
ThumbnailCanvas.SetValue(Canvas.LeftProperty, (double)_verticalOffset);
double v = (double)_velocity;
v = v / 1.1;
_velocity = (int)v;
if (_verticalOffset > 200)
{
_scrollCounter = 0;
_velocity = 0;
_scrollDistance = -(int)(_verticalOffset);
}
}
}
If you need more details let me know. In the meantime, go over and check out the application and let me know what you think!
Thank you,
–Mike







