ScrollBar: support smooth scrolling via keyboard

This commit is contained in:
Karl Tauber
2020-08-12 16:13:09 +02:00
parent 1f2622819a
commit 3573188025
2 changed files with 77 additions and 14 deletions

View File

@@ -477,6 +477,7 @@ public class FlatScrollBarUI
if( useValueIsAdjusting ) if( useValueIsAdjusting )
scrollbar.setValueIsAdjusting( true ); scrollbar.setValueIsAdjusting( true );
// remember current scrollbar value so that we can start scroll animation from there
int oldValue = scrollbar.getValue(); int oldValue = scrollbar.getValue();
// if invoked while animation is running, calculation of new value // if invoked while animation is running, calculation of new value
@@ -488,31 +489,51 @@ public class FlatScrollBarUI
// do not use animation if started dragging thumb // do not use animation if started dragging thumb
if( isDragging ) { if( isDragging ) {
// do not clear valueIsAdjusting here
inRunAndSetValueAnimated = false; inRunAndSetValueAnimated = false;
return; return;
} }
int newValue = scrollbar.getValue(); int newValue = scrollbar.getValue();
if( newValue != oldValue ) { if( newValue != oldValue ) {
scrollbar.setValue( oldValue ); // start scroll animation if value has changed
setValueAnimated( oldValue, newValue );
setValueAnimated( newValue ); } else {
} else if( useValueIsAdjusting ) // clear valueIsAdjusting if value has not changed
scrollbar.setValueIsAdjusting( false ); if( useValueIsAdjusting )
scrollbar.setValueIsAdjusting( false );
}
inRunAndSetValueAnimated = false; inRunAndSetValueAnimated = false;
} }
private boolean inRunAndSetValueAnimated; private boolean inRunAndSetValueAnimated;
private Animator animator; private Animator animator;
private int startValue = Integer.MIN_VALUE;
private int targetValue = Integer.MIN_VALUE; private int targetValue = Integer.MIN_VALUE;
private int delta;
private boolean useValueIsAdjusting = true; private boolean useValueIsAdjusting = true;
public void setValueAnimated( int value ) { public void setValueAnimated( int initialValue, int value ) {
// do some check if animation already running
if( animator != null && animator.isRunning() && targetValue != Integer.MIN_VALUE ) {
// ignore requests if animation still running and scroll direction is the same
// and new value is within currently running animation
// (this may occur when repeat-scrolling via keyboard)
if( value == targetValue ||
(value > startValue && value < targetValue) || // scroll down/right
(value < startValue && value > targetValue) ) // scroll up/left
return;
}
if( useValueIsAdjusting ) if( useValueIsAdjusting )
scrollbar.setValueIsAdjusting( true ); scrollbar.setValueIsAdjusting( true );
// set scrollbar value to initial value
scrollbar.setValue( initialValue );
startValue = initialValue;
targetValue = value;
// create animator // create animator
if( animator == null ) { if( animator == null ) {
int duration = FlatUIUtils.getUIInt( "ScrollPane.smoothScrolling.duration", 200 ); int duration = FlatUIUtils.getUIInt( "ScrollPane.smoothScrolling.duration", 200 );
@@ -521,7 +542,7 @@ public class FlatScrollBarUI
animator = new Animator( duration, fraction -> { animator = new Animator( duration, fraction -> {
if( scrollbar == null || !scrollbar.isShowing() ) { if( scrollbar == null || !scrollbar.isShowing() ) {
animator.cancel(); animator.stop();
return; return;
} }
@@ -530,10 +551,11 @@ public class FlatScrollBarUI
if( useValueIsAdjusting && !scrollbar.getValueIsAdjusting() ) if( useValueIsAdjusting && !scrollbar.getValueIsAdjusting() )
scrollbar.setValueIsAdjusting( true ); scrollbar.setValueIsAdjusting( true );
scrollbar.setValue( targetValue - delta + Math.round( delta * fraction ) ); scrollbar.setValue( startValue + Math.round( (targetValue - startValue) * fraction ) );
}, () -> { }, () -> {
targetValue = Integer.MIN_VALUE; startValue = targetValue = Integer.MIN_VALUE;
if( useValueIsAdjusting )
if( useValueIsAdjusting && scrollbar != null )
scrollbar.setValueIsAdjusting( false ); scrollbar.setValueIsAdjusting( false );
}); });
@@ -543,9 +565,7 @@ public class FlatScrollBarUI
: new CubicBezierEasing( 0.5f, 0.5f, 0.5f, 1 ) ); : new CubicBezierEasing( 0.5f, 0.5f, 0.5f, 1 ) );
} }
targetValue = value; // restart animator
delta = targetValue - scrollbar.getValue();
animator.cancel(); animator.cancel();
animator.start(); animator.start();
} }

View File

@@ -453,6 +453,49 @@ public class FlatScrollPaneUI
return false; return false;
} }
@Override
protected void syncScrollPaneWithViewport() {
if( isSmoothScrollingEnabled() ) {
runAndSyncScrollBarValueAnimated( scrollpane.getVerticalScrollBar(), 0, () -> {
runAndSyncScrollBarValueAnimated( scrollpane.getHorizontalScrollBar(), 1, () -> {
super.syncScrollPaneWithViewport();
} );
} );
} else
super.syncScrollPaneWithViewport();
}
private void runAndSyncScrollBarValueAnimated( JScrollBar sb, int i, Runnable r ) {
if( inRunAndSyncValueAnimated[i] || sb == null ) {
r.run();
return;
}
inRunAndSyncValueAnimated[i] = true;
int oldValue = sb.getValue();
int oldVisibleAmount = sb.getVisibleAmount();
int oldMinimum = sb.getMinimum();
int oldMaximum = sb.getMaximum();
r.run();
int newValue = sb.getValue();
if( newValue != oldValue &&
sb.getVisibleAmount() == oldVisibleAmount &&
sb.getMinimum() == oldMinimum &&
sb.getMaximum() == oldMaximum &&
sb.getUI() instanceof FlatScrollBarUI )
{
((FlatScrollBarUI)sb.getUI()).setValueAnimated( oldValue, newValue );
}
inRunAndSyncValueAnimated[i] = false;
}
private final boolean[] inRunAndSyncValueAnimated = new boolean[2];
//---- class Handler ------------------------------------------------------ //---- class Handler ------------------------------------------------------
/** /**