Skip to content

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;
  }
}

Code result

Focus transition

Made with ❤️