Special flow
Fern also provides a special flow called FocusFlow
It allows you to create a focus-based animation, where the transition is only active when it is focused on.
Usage
java
Flow<?> focus = Fern.focus(
Fern.transition(200).ease(Easings::easeOutCubic)
);
protected void paintComponent(Graphics gui) {
focus.tick(gui, delta);
focus.setFocus(/* mouse is hovering, for example */);
focus.active(); // Optional<Transitionable<?>>
}
TIP
Blur transition will be reversed focus transition
But you can also provide it separately as second parameter
java
Flow<?> focus = Fern.focus(
Fern.transition(200).ease(Easings::easeOutCubic),
Fern.transition(100).reverse() // faster transition without easing
);
Lets build something
We can create a simple square in the center of the screen that changes its color and corner roundness when hovered over.
java
class Square extends JPanel {
private final int size = 128;
private final double delta;
private Mouse mouse = new Mouse();
private FocusFlow<?> focus = Fern.focus(
Fern.transition(500)
.ease(Easings::easeOutQuad));
public JPanel(double delta) {
this.delta = delta;
setBackground(new Color(16, 16, 20));
addMouseMotionListener(mouse);
}
@Override
protected void paintComponent(Graphics gui) {
super.paintComponent(gui);
// get center of the screen
int x = getWidth() / 2 - size / 2;
int y = getHeight() / 2 - size / 2;
focus.tick(delta);
focus.setFocus(mouse.isHoveringSquare(x, y, size));
int[] radius = new int[] { 64, 64 };
focus.active().ifPresent(transition -> {
Color color = new Color(80, 0, 255, transition.lerp(100, 255));
gui.setColor(color);
radius[0] = transition.lerp(64, 16);
radius[1] = transition.lerp(64, 16);
});
gui.fillRoundRect(x, y, size, size, radius[0], radius[1]);
}
}
java
public class FocusSample {
// frames per second
private static int FPS = 30;
// time between frames
private static int delta = 1000 / FPS;
public static void main(String[] args) {
JFrame frame = new JFrame("fern");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(512, 512);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.add(new Sqaure(delta));
new Timer(delta, a -> frame.repaint()).start();
}
}
java
// Just a simple mouse listener
class Mouse extends MouseMotionAdapter {
private int x;
private int y;
@Override
public void mouseMoved(MouseEvent e) {
this.x = e.getX();
this.y = e.getY();
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public boolean isHoveringSquare(int x, int y, int size) {
return this.x >= x &&
this.y >= y &&
this.x <= x + size &&
this.y <= y + size;
}
}