While we are at it, here is a simple class a created long ago (when the iPhone came out :-) to immitate it's fling scrolling. It does not need the TimingFramework and is capable of smoothly scrolling any JScrollPane. To use it with a particular scroll pane simply create a FlingScroller passing the scroll pane as argument. All the rest are handled automatically by the class. NOTE that this was created for demonstration properties and it is only capable of fling scrolling on the vertical direction.
It should not be very difficult though to extend it.
/**
*
*/
package flingscroller;
import java.awt.Point;
import java.awt.event.*;
import javax.swing.JScrollPane;
import javax.swing.Timer;
/**
* @author antk
*
*/
public class FlingScroller
implements
MouseListener,
MouseMotionListener,
ActionListener
{
private JScrollPane m_scroller;
public FlingScroller( JScrollPane scroller)
{
m_scroller = scroller;
m_scroller.getViewport().getView().addMouseListener( this);
m_scroller.getViewport().getView().addMouseMotionListener( this);
}
/* (non-Javadoc)
* @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
*/
@Override
public void mouseClicked( MouseEvent e)
{
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
*/
@Override
public void mouseEntered( MouseEvent e)
{
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
*/
@Override
public void mouseExited( MouseEvent e)
{
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
*/
@Override
public void mousePressed( MouseEvent e)
{
if ( m_animator != null && m_animator.isRunning())
m_animator.stop();
m_grabX = e.getPoint().x - m_scroller.getViewport().getViewPosition().x;
m_grabY = e.getPoint().y - m_scroller.getViewport().getViewPosition().y;
m_grabPoint = m_scroller.getViewport().getViewPosition();
m_previousPos = m_scroller.getViewport().getViewPosition();
m_dragging = true;
}
/* (non-Javadoc)
* @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
*/
@Override
public void mouseReleased( MouseEvent e)
{
if ( ! m_dragging )
return;
m_dragging = false;
timerStartMotion();
}
/* (non-Javadoc)
* @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
*/
@Override
public void mouseDragged( MouseEvent e)
{
int newX = e.getPoint().x - m_scroller.getViewport().getViewPosition().x;
int newY = e.getPoint().y - m_scroller.getViewport().getViewPosition().y;
long now = System.currentTimeMillis();
Point newPos = new Point( m_grabPoint.x - ( newX - m_grabX), m_grabPoint.y - (newY - m_grabY));
if ( newPos.x < 0)
newPos.x = 0;
if ( newPos.y < 0)
newPos.y = 0;
if ( newPos.x+ m_scroller.getViewport().getWidth() > m_scroller.getViewport().getView().getWidth())
newPos.x = m_scroller.getViewport().getView().getWidth() - m_scroller.getViewport().getWidth();
if ( newPos.y+ m_scroller.getViewport().getHeight() > m_scroller.getViewport().getView().getHeight())
newPos.y = m_scroller.getViewport().getView().getHeight() - m_scroller.getViewport().getHeight();
long dt = now - m_previousPosTimestamp;
if ( dt > 20)
{
m_verticalVelocity = ( newPos.y - m_previousPos.y)/(double)dt;
m_previousPos = m_scroller.getViewport().getViewPosition();
m_previousPosTimestamp = now;
}
m_scroller.getViewport().setViewPosition( newPos);
}
Point m_previousPos = new Point();
/**
* The time at which the viewport was at the previous position.
*/
private long m_previousPosTimestamp;
private double m_verticalVelocity;
/* (non-Javadoc)
* @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
*/
@Override
public void mouseMoved( MouseEvent e)
{
// TODO Auto-generated method stub
}
private double DECELERATION = 0.1;
private Timer m_animator;
private void timerStartMotion()
{
if ( m_animator != null && m_animator.isRunning())
m_animator.stop();
m_animator = new Timer(1 , this);
m_animator.setRepeats( true);
m_animator.start();
}
//
// State variables.
//
private boolean m_dragging;
private Point m_grabPoint;
private int m_grabX;
private int m_grabY;
/* (non-Javadoc)
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
@Override
public void actionPerformed( ActionEvent e)
{
Point p = m_scroller.getViewport().getViewPosition();
double y = p.y + m_verticalVelocity;
if ( m_verticalVelocity < 0)
m_verticalVelocity += DECELERATION;
else if ( m_verticalVelocity > 0)
m_verticalVelocity -= DECELERATION;
if ( y<0) {
y = 0;
m_verticalVelocity = -m_verticalVelocity;
// m_animator.stop();
}
if ( (y + m_scroller.getViewport().getHeight()) > m_scroller.getViewport().getView().getHeight())
{
y = m_scroller.getViewport().getView().getHeight() - m_scroller.getViewport().getHeight();
m_animator.stop();
}
if ( Math.abs( m_verticalVelocity) < 0.0005)
{
m_animator.stop();
}
p.y = (int)Math.rint( y);
m_scroller.getViewport().setViewPosition( p);
}
}
|