SwingFluidSwipeAPI
Extend the Swing framework with fluid-swipe gesture support. Our aim is to reduce the gap between native applications and AWT/Swing applications, providing a more consistent and pleasant UI/UX with animated feedback.
IntelliJ.Demo.mov
macOS/OS X case
Support for the fluid-swipe gesture that is largely used for navigation in many AppKit-built programs, notably Safari, Xcode and Photos, is not offered by JDK – in fact, as far as swipe gestures are concerned, the JDK supports only the discrete ones (namely, 3-finger swipe gestures via com.apple.eawt.event)
Usage
This project is available on Maven Central:
Maven
<dependency> <groupId>eu.giulianogorgone</groupId> <artifactId>fluidswipe-core</artifactId> <version>1.2.0</version> </dependency>
Gradle
implementation("eu.giulianogorgone:fluidswipe-core:1.2.0")To start event monitoring:
FluidSwipe.startEventMonitoring();
Please note that the above function internally calls Toolkit.getDefaultToolkit().
To stop instead event monitoring:
FluidSwipe.stopEventMonitoring();
Adding listeners and blocking unwanted incoming gestures
import javax.swing.*; public class NavigableComponent extends JComponent implements FluidSwipeVetoer { // [...] protected void configGestures() { FluidSwipe.addListenerTo(this, new FluidSwipeAdapter() { @Override public void fluidSwipeEnded(final FluidSwipeEvent e) { if (e.getGestureState() == FluidSwipeEvent.State.SUCCESS) { if (contentDirection == FluidSwipeEvent.Direction.LEFT_TO_RIGHT) this.navigateBack(); else this.navigateForward(); } } }); } // [...] @Override public boolean permitFluidSwipeGesture(final FluidSwipeEvent e) { if (e.getLogicalGestureDirection() == FluidSwipeEvent.Direction.LEFT_TO_RIGHT) return this.canNavigateBack(); else return this.canNavigateForward(); } }
A runnable sample is also provided here
OS settings (macOS/OS X)
In order for fluid-swipe gesture to work, the following conditions must be met, in normal circumstances:
- If using a supported trackpad:
System Preferences/System Settings>Accessibility>Pointer Control/Mouse & Trackpad>Trackpad Options...>Use trackpad for scrolling/Scrollingis flagged onSystem Preferences/System Settings>Trackpad>More Gestures>Swipe with Two or Three FingersorScroll Left or Right with Two Fingersis selected
- If using a mouse such a Magic Mouse:
System Preferences/System Settings>Accessibility>Pointer Control/Mouse & Trackpad>Mouse Options...>Use mouse for scrolling/Scrollingis flagged onSystem Preferences/System Settings>Trackpad>More Gestures>Swipe with One or Two FingersorScroll Left or Right with One Fingeris selected
Glossary
- "veto a fluid-swipe": consists in preventing the performed physical swipe gesture from being interpreted as fluid-swipe, in which case this gesture will be handled as usual (i.e., as a horizontal scroll gesture, thus a set of
MouseWheelEventwill be dispatched). - "swipeable component": a Swing component enabled to receive fluid-swipe events, i.e., at least a proper listener has been attached to this component via
FluidSwipe#addListenerTo - "vetoer component": a Swing component that implements
FluidSwipeVetoer; it has the facility to veto fluid-swipe event.
Avoiding common pitfalls
Conflicting gestures — implementation of a scroll/fluid-swipe coexistence mechanism
The physical gesture that may start a fluid-swipe can also be interpreted as a horizontal scroll gesture.
It is absolutely recommended that components listening for scroll-wheel events implement FluidSwipeVetoer; not to veto an incoming fluid-swipe results in MouseWheelEvent not to be dispatching as expected.
Ideally, fluid-swipe gesture should have a lower priority than scroll event.
We strongly encourage you to consider the following example involving a JScrollPane.
public class FluidSwipeAwareJScrollPane extends JScrollPane implements FluidSwipeVetoer { // [...] @Override public boolean permitFluidSwipeGesture(FluidSwipeEvent e) { final FluidSwipeEvent.Direction contentDirection = e.getLogicalGestureDirection(); if (horizontalScrollBar == null || getHorizontalScrollBarPolicy() == HORIZONTAL_SCROLLBAR_NEVER) return true; return (contentDirection == FluidSwipeEvent.Direction.RIGHT_TO_LEFT && (horizontalScrollBar.getValue() + horizontalScrollBar.getModel().getExtent()) == horizontalScrollBar.getMaximum()) || (contentDirection == FluidSwipeEvent.Direction.LEFT_TO_RIGHT && horizontalScrollBar.getValue() == horizontalScrollBar.getMinimum()); } }
Starting from version 1.2.0, the above logic is default for JScrollPane; to override it, extend JScrollPane and implement FluidSwipeVetoer.
HW/SW Requirements
- OS:macOS/OS X >= 10.13.
- Hardware: Apple Magic Trackpad, Mac laptop's built-in trackpad et similia. Apple Magic Mouse is expected to work, but it has not yet been tested — unfortunately, we do not own this device.
Contribute
If any problem is encountered, please submit an issue and eventually propose a solution.
Guidelines
Ensure to provide also:
- information about the running machine and environment (which version of macOS/OS X, JDK, architecture)
- steps to reproduce the malfunction (ideally an SCCE)
- a brief but complete written description of the issue.
Avoid please:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conducts which could reasonably be considered inappropriate in a professional setting
Any content deemed as abuse or spam will be reported to GitHub.
why not?
- ensure that Magic Mouse works flawlessly — testers are welcome
- add other platform support
License
This project is licensed under the Apache 2.0 license.